@google/gemini-cli 0.1.18 → 0.1.19-nightly.250814.514e883a

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 (254) hide show
  1. package/README.md +199 -132
  2. package/dist/package.json +5 -3
  3. package/dist/src/commands/mcp/add.d.ts +7 -0
  4. package/dist/src/commands/mcp/add.js +155 -0
  5. package/dist/src/commands/mcp/add.js.map +1 -0
  6. package/dist/src/commands/mcp/list.d.ts +8 -0
  7. package/dist/src/commands/mcp/list.js +110 -0
  8. package/dist/src/commands/mcp/list.js.map +1 -0
  9. package/dist/src/commands/mcp/remove.d.ts +7 -0
  10. package/dist/src/commands/mcp/remove.js +44 -0
  11. package/dist/src/commands/mcp/remove.js.map +1 -0
  12. package/dist/src/commands/mcp.d.ts +7 -0
  13. package/dist/src/commands/mcp.js +23 -0
  14. package/dist/src/commands/mcp.js.map +1 -0
  15. package/dist/src/config/config.d.ts +2 -3
  16. package/dist/src/config/config.js +123 -58
  17. package/dist/src/config/config.js.map +1 -1
  18. package/dist/src/config/keyBindings.d.ts +66 -0
  19. package/dist/src/config/keyBindings.js +140 -0
  20. package/dist/src/config/keyBindings.js.map +1 -0
  21. package/dist/src/config/settings.d.ts +3 -50
  22. package/dist/src/config/settings.js +17 -1
  23. package/dist/src/config/settings.js.map +1 -1
  24. package/dist/src/config/settingsSchema.d.ts +488 -0
  25. package/dist/src/config/settingsSchema.js +461 -0
  26. package/dist/src/config/settingsSchema.js.map +1 -0
  27. package/dist/src/config/trustedFolders.d.ts +36 -0
  28. package/dist/src/config/trustedFolders.js +112 -0
  29. package/dist/src/config/trustedFolders.js.map +1 -0
  30. package/dist/src/gemini.js +15 -31
  31. package/dist/src/gemini.js.map +1 -1
  32. package/dist/src/generated/git-commit.d.ts +1 -1
  33. package/dist/src/generated/git-commit.js +1 -1
  34. package/dist/src/nonInteractiveCli.js +2 -4
  35. package/dist/src/nonInteractiveCli.js.map +1 -1
  36. package/dist/src/services/BuiltinCommandLoader.js +5 -2
  37. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  38. package/dist/src/ui/App.js +112 -35
  39. package/dist/src/ui/App.js.map +1 -1
  40. package/dist/src/ui/IdeIntegrationNudge.d.ts +16 -0
  41. package/dist/src/ui/IdeIntegrationNudge.js +52 -0
  42. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -0
  43. package/dist/src/ui/commands/chatCommand.js +15 -0
  44. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  45. package/dist/src/ui/commands/directoryCommand.js +2 -4
  46. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  47. package/dist/src/ui/commands/ideCommand.js +59 -5
  48. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  49. package/dist/src/ui/commands/mcpCommand.js +4 -0
  50. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  51. package/dist/src/ui/commands/settingsCommand.d.ts +7 -0
  52. package/dist/src/ui/commands/settingsCommand.js +16 -0
  53. package/dist/src/ui/commands/settingsCommand.js.map +1 -0
  54. package/dist/src/ui/commands/setupGithubCommand.js +86 -19
  55. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  56. package/dist/src/ui/commands/terminalSetupCommand.d.ts +13 -0
  57. package/dist/src/ui/commands/terminalSetupCommand.js +41 -0
  58. package/dist/src/ui/commands/terminalSetupCommand.js.map +1 -0
  59. package/dist/src/ui/commands/types.d.ts +14 -2
  60. package/dist/src/ui/commands/types.js.map +1 -1
  61. package/dist/src/ui/components/AsciiArt.d.ts +1 -0
  62. package/dist/src/ui/components/AsciiArt.js +10 -0
  63. package/dist/src/ui/components/AsciiArt.js.map +1 -1
  64. package/dist/src/ui/components/AuthDialog.js +5 -4
  65. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  66. package/dist/src/ui/components/AuthInProgress.js +6 -5
  67. package/dist/src/ui/components/AuthInProgress.js.map +1 -1
  68. package/dist/src/ui/components/ContextSummaryDisplay.js +21 -24
  69. package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
  70. package/dist/src/ui/components/ContextUsageDisplay.d.ts +9 -0
  71. package/dist/src/ui/components/ContextUsageDisplay.js +14 -0
  72. package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -0
  73. package/dist/src/ui/components/DebugProfiler.js +5 -4
  74. package/dist/src/ui/components/DebugProfiler.js.map +1 -1
  75. package/dist/src/ui/components/EditorSettingsDialog.js +6 -5
  76. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  77. package/dist/src/ui/components/FolderTrustDialog.d.ts +16 -0
  78. package/dist/src/ui/components/FolderTrustDialog.js +39 -0
  79. package/dist/src/ui/components/FolderTrustDialog.js.map +1 -0
  80. package/dist/src/ui/components/Footer.js +14 -5
  81. package/dist/src/ui/components/Footer.js.map +1 -1
  82. package/dist/src/ui/components/Header.d.ts +0 -1
  83. package/dist/src/ui/components/Header.js +13 -5
  84. package/dist/src/ui/components/Header.js.map +1 -1
  85. package/dist/src/ui/components/InputPrompt.d.ts +1 -0
  86. package/dist/src/ui/components/InputPrompt.js +97 -35
  87. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  88. package/dist/src/ui/components/LoadingIndicator.js +10 -5
  89. package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
  90. package/dist/src/ui/components/SettingsDialog.d.ts +14 -0
  91. package/dist/src/ui/components/SettingsDialog.js +249 -0
  92. package/dist/src/ui/components/SettingsDialog.js.map +1 -0
  93. package/dist/src/ui/components/ShellConfirmationDialog.js +5 -4
  94. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  95. package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
  96. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  97. package/dist/src/ui/components/ThemeDialog.js +10 -20
  98. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  99. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +34 -13
  100. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  101. package/dist/src/ui/components/shared/RadioButtonSelect.js +10 -8
  102. package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
  103. package/dist/src/ui/components/shared/text-buffer.d.ts +17 -4
  104. package/dist/src/ui/components/shared/text-buffer.js +224 -70
  105. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  106. package/dist/src/ui/components/shared/vim-buffer-actions.js +139 -152
  107. package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -1
  108. package/dist/src/ui/contexts/SettingsContext.d.ts +9 -0
  109. package/dist/src/ui/contexts/SettingsContext.js +15 -0
  110. package/dist/src/ui/contexts/SettingsContext.js.map +1 -0
  111. package/dist/src/ui/hooks/atCommandProcessor.js +7 -4
  112. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  113. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +6 -2
  114. package/dist/src/ui/hooks/slashCommandProcessor.js +101 -49
  115. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  116. package/dist/src/ui/hooks/useAtCompletion.js +4 -1
  117. package/dist/src/ui/hooks/useAtCompletion.js.map +1 -1
  118. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +5 -5
  119. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  120. package/dist/src/ui/hooks/useFocus.d.ts +4 -0
  121. package/dist/src/ui/hooks/useFocus.js +4 -4
  122. package/dist/src/ui/hooks/useFocus.js.map +1 -1
  123. package/dist/src/ui/hooks/useFolderTrust.d.ts +12 -0
  124. package/dist/src/ui/hooks/useFolderTrust.js +37 -0
  125. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -0
  126. package/dist/src/ui/hooks/useGeminiStream.d.ts +2 -1
  127. package/dist/src/ui/hooks/useGeminiStream.js +34 -21
  128. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  129. package/dist/src/ui/hooks/useKeypress.d.ts +9 -1
  130. package/dist/src/ui/hooks/useKeypress.js +197 -8
  131. package/dist/src/ui/hooks/useKeypress.js.map +1 -1
  132. package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +15 -0
  133. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +20 -0
  134. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +1 -0
  135. package/dist/src/ui/hooks/usePhraseCycler.js +2 -2
  136. package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
  137. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +1 -1
  138. package/dist/src/ui/hooks/useReactToolScheduler.js +15 -15
  139. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  140. package/dist/src/ui/hooks/useSettingsCommand.d.ts +10 -0
  141. package/dist/src/ui/hooks/useSettingsCommand.js +21 -0
  142. package/dist/src/ui/hooks/useSettingsCommand.js.map +1 -0
  143. package/dist/src/ui/keyMatchers.d.ts +26 -0
  144. package/dist/src/ui/keyMatchers.js +68 -0
  145. package/dist/src/ui/keyMatchers.js.map +1 -0
  146. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +5 -4
  147. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
  148. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +5 -4
  149. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +1 -1
  150. package/dist/src/ui/privacy/GeminiPrivacyNotice.js +5 -4
  151. package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +1 -1
  152. package/dist/src/ui/semantic-colors.d.ts +7 -0
  153. package/dist/src/ui/semantic-colors.js +24 -0
  154. package/dist/src/ui/semantic-colors.js.map +1 -0
  155. package/dist/src/ui/themes/ansi-light.js +2 -1
  156. package/dist/src/ui/themes/ansi-light.js.map +1 -1
  157. package/dist/src/ui/themes/ansi.js +2 -1
  158. package/dist/src/ui/themes/ansi.js.map +1 -1
  159. package/dist/src/ui/themes/atom-one-dark.js +2 -1
  160. package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
  161. package/dist/src/ui/themes/ayu-light.js +2 -1
  162. package/dist/src/ui/themes/ayu-light.js.map +1 -1
  163. package/dist/src/ui/themes/ayu.js +2 -1
  164. package/dist/src/ui/themes/ayu.js.map +1 -1
  165. package/dist/src/ui/themes/default-light.js +2 -1
  166. package/dist/src/ui/themes/default-light.js.map +1 -1
  167. package/dist/src/ui/themes/default.js +2 -1
  168. package/dist/src/ui/themes/default.js.map +1 -1
  169. package/dist/src/ui/themes/dracula.js +2 -1
  170. package/dist/src/ui/themes/dracula.js.map +1 -1
  171. package/dist/src/ui/themes/github-dark.js +2 -1
  172. package/dist/src/ui/themes/github-dark.js.map +1 -1
  173. package/dist/src/ui/themes/github-light.js +2 -1
  174. package/dist/src/ui/themes/github-light.js.map +1 -1
  175. package/dist/src/ui/themes/googlecode.js +2 -1
  176. package/dist/src/ui/themes/googlecode.js.map +1 -1
  177. package/dist/src/ui/themes/no-color.js +30 -1
  178. package/dist/src/ui/themes/no-color.js.map +1 -1
  179. package/dist/src/ui/themes/semantic-tokens.d.ts +37 -0
  180. package/dist/src/ui/themes/semantic-tokens.js +94 -0
  181. package/dist/src/ui/themes/semantic-tokens.js.map +1 -0
  182. package/dist/src/ui/themes/shades-of-purple.js +2 -1
  183. package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
  184. package/dist/src/ui/themes/theme-manager.d.ts +6 -0
  185. package/dist/src/ui/themes/theme-manager.js +7 -0
  186. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  187. package/dist/src/ui/themes/theme.d.ts +45 -2
  188. package/dist/src/ui/themes/theme.js +92 -107
  189. package/dist/src/ui/themes/theme.js.map +1 -1
  190. package/dist/src/ui/themes/xcode.js +2 -1
  191. package/dist/src/ui/themes/xcode.js.map +1 -1
  192. package/dist/src/ui/types.d.ts +1 -1
  193. package/dist/src/ui/utils/CodeColorizer.d.ts +2 -1
  194. package/dist/src/ui/utils/CodeColorizer.js +4 -3
  195. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  196. package/dist/src/ui/utils/ConsolePatcher.d.ts +1 -0
  197. package/dist/src/ui/utils/ConsolePatcher.js +3 -0
  198. package/dist/src/ui/utils/ConsolePatcher.js.map +1 -1
  199. package/dist/src/ui/utils/MarkdownDisplay.js +4 -2
  200. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  201. package/dist/src/ui/utils/commandUtils.d.ts +1 -0
  202. package/dist/src/ui/utils/commandUtils.js +22 -1
  203. package/dist/src/ui/utils/commandUtils.js.map +1 -1
  204. package/dist/src/ui/utils/isNarrowWidth.d.ts +6 -0
  205. package/dist/src/ui/utils/isNarrowWidth.js +9 -0
  206. package/dist/src/ui/utils/isNarrowWidth.js.map +1 -0
  207. package/dist/src/ui/utils/kittyProtocolDetector.d.ts +13 -0
  208. package/dist/src/ui/utils/kittyProtocolDetector.js +88 -0
  209. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -0
  210. package/dist/src/ui/utils/platformConstants.d.ts +38 -0
  211. package/dist/src/ui/utils/platformConstants.js +39 -0
  212. package/dist/src/ui/utils/platformConstants.js.map +1 -0
  213. package/dist/src/ui/utils/terminalSetup.d.ts +30 -0
  214. package/dist/src/ui/utils/terminalSetup.js +281 -0
  215. package/dist/src/ui/utils/terminalSetup.js.map +1 -0
  216. package/dist/src/utils/checks.d.ts +19 -0
  217. package/dist/src/utils/checks.js +24 -0
  218. package/dist/src/utils/checks.js.map +1 -0
  219. package/dist/src/utils/cleanup.d.ts +2 -2
  220. package/dist/src/utils/cleanup.js +2 -2
  221. package/dist/src/utils/cleanup.js.map +1 -1
  222. package/dist/src/utils/dialogScopeUtils.d.ts +31 -0
  223. package/dist/src/utils/dialogScopeUtils.js +48 -0
  224. package/dist/src/utils/dialogScopeUtils.js.map +1 -0
  225. package/dist/src/utils/gitUtils.d.ts +21 -1
  226. package/dist/src/utils/gitUtils.js +68 -3
  227. package/dist/src/utils/gitUtils.js.map +1 -1
  228. package/dist/src/utils/sandbox.js +426 -405
  229. package/dist/src/utils/sandbox.js.map +1 -1
  230. package/dist/src/utils/settingsUtils.d.ts +126 -0
  231. package/dist/src/utils/settingsUtils.js +327 -0
  232. package/dist/src/utils/settingsUtils.js.map +1 -0
  233. package/dist/src/zed-integration/acp.d.ts +63 -0
  234. package/dist/src/{acp → zed-integration}/acp.js +76 -44
  235. package/dist/src/zed-integration/acp.js.map +1 -0
  236. package/dist/src/zed-integration/schema.d.ts +11679 -0
  237. package/dist/src/zed-integration/schema.js +305 -0
  238. package/dist/src/zed-integration/schema.js.map +1 -0
  239. package/dist/src/zed-integration/zedIntegration.d.ts +10 -0
  240. package/dist/src/{acp/acpPeer.js → zed-integration/zedIntegration.js} +323 -169
  241. package/dist/src/zed-integration/zedIntegration.js.map +1 -0
  242. package/dist/tsconfig.tsbuildinfo +1 -1
  243. package/package.json +6 -4
  244. package/dist/google-gemini-cli-0.1.17.tgz +0 -0
  245. package/dist/src/acp/acp.d.ts +0 -208
  246. package/dist/src/acp/acp.js.map +0 -1
  247. package/dist/src/acp/acpPeer.d.ts +0 -8
  248. package/dist/src/acp/acpPeer.js.map +0 -1
  249. package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +0 -12
  250. package/dist/src/ui/components/IDEContextDetailDisplay.js +0 -12
  251. package/dist/src/ui/components/IDEContextDetailDisplay.js.map +0 -1
  252. package/dist/src/ui/utils/errorParsing.d.ts +0 -7
  253. package/dist/src/ui/utils/errorParsing.js +0 -90
  254. package/dist/src/ui/utils/errorParsing.js.map +0 -1
@@ -3,13 +3,16 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, } from '@google/gemini-cli-core';
6
+ import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, MCPServerConfig, } from '@google/gemini-cli-core';
7
7
  import * as acp from './acp.js';
8
8
  import { Readable, Writable } from 'node:stream';
9
9
  import { SettingScope } from '../config/settings.js';
10
10
  import * as fs from 'fs/promises';
11
11
  import * as path from 'path';
12
- export async function runAcpPeer(config, settings) {
12
+ import { z } from 'zod';
13
+ import { randomUUID } from 'crypto';
14
+ import { loadCliConfig } from '../config/config.js';
15
+ export async function runZedIntegration(config, settings, extensions, argv) {
13
16
  const stdout = Writable.toWeb(process.stdout);
14
17
  const stdin = Readable.toWeb(process.stdin);
15
18
  // Stdout is used to send messages to the client, so console.log/console.info
@@ -17,61 +20,138 @@ export async function runAcpPeer(config, settings) {
17
20
  console.log = console.error;
18
21
  console.info = console.error;
19
22
  console.debug = console.error;
20
- new acp.ClientConnection((client) => new GeminiAgent(config, settings, client), stdout, stdin);
23
+ new acp.AgentSideConnection((client) => new GeminiAgent(config, settings, extensions, argv, client), stdout, stdin);
21
24
  }
22
25
  class GeminiAgent {
23
26
  config;
24
27
  settings;
28
+ extensions;
29
+ argv;
25
30
  client;
26
- chat;
27
- pendingSend;
28
- constructor(config, settings, client) {
31
+ sessions = new Map();
32
+ constructor(config, settings, extensions, argv, client) {
29
33
  this.config = config;
30
34
  this.settings = settings;
35
+ this.extensions = extensions;
36
+ this.argv = argv;
31
37
  this.client = client;
32
38
  }
33
- async initialize(_) {
39
+ async initialize(_args) {
40
+ const authMethods = [
41
+ {
42
+ id: AuthType.LOGIN_WITH_GOOGLE,
43
+ name: 'Log in with Google',
44
+ description: null,
45
+ },
46
+ {
47
+ id: AuthType.USE_GEMINI,
48
+ name: 'Use Gemini API key',
49
+ description: 'Requires setting the `GEMINI_API_KEY` environment variable',
50
+ },
51
+ {
52
+ id: AuthType.USE_VERTEX_AI,
53
+ name: 'Vertex AI',
54
+ description: null,
55
+ },
56
+ ];
57
+ return {
58
+ protocolVersion: acp.PROTOCOL_VERSION,
59
+ authMethods,
60
+ agentCapabilities: {
61
+ loadSession: false,
62
+ },
63
+ };
64
+ }
65
+ async authenticate({ methodId }) {
66
+ const method = z.nativeEnum(AuthType).parse(methodId);
67
+ await clearCachedCredentialFile();
68
+ await this.config.refreshAuth(method);
69
+ this.settings.setValue(SettingScope.User, 'selectedAuthType', method);
70
+ }
71
+ async newSession({ cwd, mcpServers, }) {
72
+ const sessionId = randomUUID();
73
+ const config = await this.newSessionConfig(sessionId, cwd, mcpServers);
34
74
  let isAuthenticated = false;
35
75
  if (this.settings.merged.selectedAuthType) {
36
76
  try {
37
- await this.config.refreshAuth(this.settings.merged.selectedAuthType);
77
+ await config.refreshAuth(this.settings.merged.selectedAuthType);
38
78
  isAuthenticated = true;
39
79
  }
40
- catch (error) {
41
- console.error('Failed to refresh auth:', error);
80
+ catch (e) {
81
+ console.error(`Authentication failed: ${e}`);
42
82
  }
43
83
  }
44
- return { protocolVersion: acp.LATEST_PROTOCOL_VERSION, isAuthenticated };
84
+ if (!isAuthenticated) {
85
+ throw acp.RequestError.authRequired();
86
+ }
87
+ const geminiClient = config.getGeminiClient();
88
+ const chat = await geminiClient.startChat();
89
+ const session = new Session(sessionId, chat, config, this.client);
90
+ this.sessions.set(sessionId, session);
91
+ return {
92
+ sessionId,
93
+ };
45
94
  }
46
- async authenticate() {
47
- await clearCachedCredentialFile();
48
- await this.config.refreshAuth(AuthType.LOGIN_WITH_GOOGLE);
49
- this.settings.setValue(SettingScope.User, 'selectedAuthType', AuthType.LOGIN_WITH_GOOGLE);
95
+ async newSessionConfig(sessionId, cwd, mcpServers) {
96
+ const mergedMcpServers = { ...this.settings.merged.mcpServers };
97
+ for (const { command, args, env: rawEnv, name } of mcpServers) {
98
+ const env = {};
99
+ for (const { name: envName, value } of rawEnv) {
100
+ env[envName] = value;
101
+ }
102
+ mergedMcpServers[name] = new MCPServerConfig(command, args, env, cwd);
103
+ }
104
+ const settings = { ...this.settings.merged, mcpServers: mergedMcpServers };
105
+ const config = await loadCliConfig(settings, this.extensions, sessionId, this.argv, cwd);
106
+ await config.initialize();
107
+ return config;
108
+ }
109
+ async cancel(params) {
110
+ const session = this.sessions.get(params.sessionId);
111
+ if (!session) {
112
+ throw new Error(`Session not found: ${params.sessionId}`);
113
+ }
114
+ await session.cancelPendingPrompt();
115
+ }
116
+ async prompt(params) {
117
+ const session = this.sessions.get(params.sessionId);
118
+ if (!session) {
119
+ throw new Error(`Session not found: ${params.sessionId}`);
120
+ }
121
+ return session.prompt(params);
50
122
  }
51
- async cancelSendMessage() {
52
- if (!this.pendingSend) {
123
+ }
124
+ class Session {
125
+ id;
126
+ chat;
127
+ config;
128
+ client;
129
+ pendingPrompt = null;
130
+ constructor(id, chat, config, client) {
131
+ this.id = id;
132
+ this.chat = chat;
133
+ this.config = config;
134
+ this.client = client;
135
+ }
136
+ async cancelPendingPrompt() {
137
+ if (!this.pendingPrompt) {
53
138
  throw new Error('Not currently generating');
54
139
  }
55
- this.pendingSend.abort();
56
- delete this.pendingSend;
140
+ this.pendingPrompt.abort();
141
+ this.pendingPrompt = null;
57
142
  }
58
- async sendUserMessage(params) {
59
- this.pendingSend?.abort();
143
+ async prompt(params) {
144
+ this.pendingPrompt?.abort();
60
145
  const pendingSend = new AbortController();
61
- this.pendingSend = pendingSend;
62
- if (!this.chat) {
63
- const geminiClient = this.config.getGeminiClient();
64
- this.chat = await geminiClient.startChat();
65
- }
146
+ this.pendingPrompt = pendingSend;
66
147
  const promptId = Math.random().toString(16).slice(2);
67
148
  const chat = this.chat;
68
- const toolRegistry = await this.config.getToolRegistry();
69
- const parts = await this.#resolveUserMessage(params, pendingSend.signal);
149
+ const parts = await this.#resolvePrompt(params.prompt, pendingSend.signal);
70
150
  let nextMessage = { role: 'user', parts };
71
151
  while (nextMessage !== null) {
72
152
  if (pendingSend.signal.aborted) {
73
153
  chat.addHistory(nextMessage);
74
- return;
154
+ return { stopReason: 'cancelled' };
75
155
  }
76
156
  const functionCalls = [];
77
157
  try {
@@ -79,17 +159,12 @@ class GeminiAgent {
79
159
  message: nextMessage?.parts ?? [],
80
160
  config: {
81
161
  abortSignal: pendingSend.signal,
82
- tools: [
83
- {
84
- functionDeclarations: toolRegistry.getFunctionDeclarations(),
85
- },
86
- ],
87
162
  },
88
163
  }, promptId);
89
164
  nextMessage = null;
90
165
  for await (const resp of responseStream) {
91
166
  if (pendingSend.signal.aborted) {
92
- return;
167
+ return { stopReason: 'cancelled' };
93
168
  }
94
169
  if (resp.candidates && resp.candidates.length > 0) {
95
170
  const candidate = resp.candidates[0];
@@ -97,10 +172,15 @@ class GeminiAgent {
97
172
  if (!part.text) {
98
173
  continue;
99
174
  }
100
- this.client.streamAssistantMessageChunk({
101
- chunk: part.thought
102
- ? { thought: part.text }
103
- : { text: part.text },
175
+ const content = {
176
+ type: 'text',
177
+ text: part.text,
178
+ };
179
+ this.sendUpdate({
180
+ sessionUpdate: part.thought
181
+ ? 'agent_thought_chunk'
182
+ : 'agent_message_chunk',
183
+ content,
104
184
  });
105
185
  }
106
186
  }
@@ -118,7 +198,7 @@ class GeminiAgent {
118
198
  if (functionCalls.length > 0) {
119
199
  const toolResponseParts = [];
120
200
  for (const fc of functionCalls) {
121
- const response = await this.#runTool(pendingSend.signal, promptId, fc);
201
+ const response = await this.runTool(pendingSend.signal, promptId, fc);
122
202
  const parts = Array.isArray(response) ? response : [response];
123
203
  for (const part of parts) {
124
204
  if (typeof part === 'string') {
@@ -132,8 +212,16 @@ class GeminiAgent {
132
212
  nextMessage = { role: 'user', parts: toolResponseParts };
133
213
  }
134
214
  }
215
+ return { stopReason: 'end_turn' };
135
216
  }
136
- async #runTool(abortSignal, promptId, fc) {
217
+ async sendUpdate(update) {
218
+ const params = {
219
+ sessionId: this.id,
220
+ update,
221
+ };
222
+ await this.client.sessionUpdate(params);
223
+ }
224
+ async runTool(abortSignal, promptId, fc) {
137
225
  const callId = fc.id ?? `${fc.name}-${Date.now()}`;
138
226
  const args = (fc.args ?? {});
139
227
  const startTime = Date.now();
@@ -167,58 +255,71 @@ class GeminiAgent {
167
255
  if (!tool) {
168
256
  return errorResponse(new Error(`Tool "${fc.name}" not found in registry.`));
169
257
  }
170
- let toolCallId;
171
- const confirmationDetails = await tool.shouldConfirmExecute(args, abortSignal);
258
+ const invocation = tool.build(args);
259
+ const confirmationDetails = await invocation.shouldConfirmExecute(abortSignal);
172
260
  if (confirmationDetails) {
173
- let content = null;
261
+ const content = [];
174
262
  if (confirmationDetails.type === 'edit') {
175
- content = {
263
+ content.push({
176
264
  type: 'diff',
177
265
  path: confirmationDetails.fileName,
178
266
  oldText: confirmationDetails.originalContent,
179
267
  newText: confirmationDetails.newContent,
180
- };
268
+ });
181
269
  }
182
- const result = await this.client.requestToolCallConfirmation({
183
- label: tool.getDescription(args),
184
- icon: tool.icon,
185
- content,
186
- confirmation: toAcpToolCallConfirmation(confirmationDetails),
187
- locations: tool.toolLocations(args),
188
- });
189
- await confirmationDetails.onConfirm(toToolCallOutcome(result.outcome));
190
- switch (result.outcome) {
191
- case 'reject':
192
- return errorResponse(new Error(`Tool "${fc.name}" not allowed to run by the user.`));
193
- case 'cancel':
270
+ const params = {
271
+ sessionId: this.id,
272
+ options: toPermissionOptions(confirmationDetails),
273
+ toolCall: {
274
+ toolCallId: callId,
275
+ status: 'pending',
276
+ title: invocation.getDescription(),
277
+ content,
278
+ locations: invocation.toolLocations(),
279
+ kind: tool.kind,
280
+ },
281
+ };
282
+ const output = await this.client.requestPermission(params);
283
+ const outcome = output.outcome.outcome === 'cancelled'
284
+ ? ToolConfirmationOutcome.Cancel
285
+ : z
286
+ .nativeEnum(ToolConfirmationOutcome)
287
+ .parse(output.outcome.optionId);
288
+ await confirmationDetails.onConfirm(outcome);
289
+ switch (outcome) {
290
+ case ToolConfirmationOutcome.Cancel:
194
291
  return errorResponse(new Error(`Tool "${fc.name}" was canceled by the user.`));
195
- case 'allow':
196
- case 'alwaysAllow':
197
- case 'alwaysAllowMcpServer':
198
- case 'alwaysAllowTool':
292
+ case ToolConfirmationOutcome.ProceedOnce:
293
+ case ToolConfirmationOutcome.ProceedAlways:
294
+ case ToolConfirmationOutcome.ProceedAlwaysServer:
295
+ case ToolConfirmationOutcome.ProceedAlwaysTool:
296
+ case ToolConfirmationOutcome.ModifyWithEditor:
199
297
  break;
200
298
  default: {
201
- const resultOutcome = result.outcome;
299
+ const resultOutcome = outcome;
202
300
  throw new Error(`Unexpected: ${resultOutcome}`);
203
301
  }
204
302
  }
205
- toolCallId = result.id;
206
303
  }
207
304
  else {
208
- const result = await this.client.pushToolCall({
209
- icon: tool.icon,
210
- label: tool.getDescription(args),
211
- locations: tool.toolLocations(args),
305
+ await this.sendUpdate({
306
+ sessionUpdate: 'tool_call',
307
+ toolCallId: callId,
308
+ status: 'in_progress',
309
+ title: invocation.getDescription(),
310
+ content: [],
311
+ locations: invocation.toolLocations(),
312
+ kind: tool.kind,
212
313
  });
213
- toolCallId = result.id;
214
314
  }
215
315
  try {
216
- const toolResult = await tool.execute(args, abortSignal);
217
- const toolCallContent = toToolCallContent(toolResult);
218
- await this.client.updateToolCall({
219
- toolCallId,
220
- status: 'finished',
221
- content: toolCallContent,
316
+ const toolResult = await invocation.execute(abortSignal);
317
+ const content = toToolCallContent(toolResult);
318
+ await this.sendUpdate({
319
+ sessionUpdate: 'tool_call_update',
320
+ toolCallId: callId,
321
+ status: 'completed',
322
+ content: content ? [content] : [],
222
323
  });
223
324
  const durationMs = Date.now() - startTime;
224
325
  logToolCall(this.config, {
@@ -234,25 +335,47 @@ class GeminiAgent {
234
335
  }
235
336
  catch (e) {
236
337
  const error = e instanceof Error ? e : new Error(String(e));
237
- await this.client.updateToolCall({
238
- toolCallId,
239
- status: 'error',
240
- content: { type: 'markdown', markdown: error.message },
338
+ await this.sendUpdate({
339
+ sessionUpdate: 'tool_call_update',
340
+ toolCallId: callId,
341
+ status: 'failed',
342
+ content: [
343
+ { type: 'content', content: { type: 'text', text: error.message } },
344
+ ],
241
345
  });
242
346
  return errorResponse(error);
243
347
  }
244
348
  }
245
- async #resolveUserMessage(message, abortSignal) {
246
- const atPathCommandParts = message.chunks.filter((part) => 'path' in part);
247
- if (atPathCommandParts.length === 0) {
248
- return message.chunks.map((chunk) => {
249
- if ('text' in chunk) {
250
- return { text: chunk.text };
349
+ async #resolvePrompt(message, abortSignal) {
350
+ const parts = message.map((part) => {
351
+ switch (part.type) {
352
+ case 'text':
353
+ return { text: part.text };
354
+ case 'resource_link':
355
+ return {
356
+ fileData: {
357
+ mimeData: part.mimeType,
358
+ name: part.name,
359
+ fileUri: part.uri,
360
+ },
361
+ };
362
+ case 'resource': {
363
+ return {
364
+ fileData: {
365
+ mimeData: part.resource.mimeType,
366
+ name: part.resource.uri,
367
+ fileUri: part.resource.uri,
368
+ },
369
+ };
251
370
  }
252
- else {
253
- throw new Error('Unexpected chunk type');
371
+ default: {
372
+ throw new Error(`Unexpected chunk type: '${part.type}'`);
254
373
  }
255
- });
374
+ }
375
+ });
376
+ const atPathCommandParts = parts.filter((part) => 'fileData' in part);
377
+ if (atPathCommandParts.length === 0) {
378
+ return parts;
256
379
  }
257
380
  // Get centralized file discovery service
258
381
  const fileDiscovery = this.config.getFileService();
@@ -268,7 +391,7 @@ class GeminiAgent {
268
391
  throw new Error('Error: read_many_files tool not found.');
269
392
  }
270
393
  for (const atPathPart of atPathCommandParts) {
271
- const pathName = atPathPart.path;
394
+ const pathName = atPathPart.fileData.fileUri;
272
395
  // Check if path should be ignored by git
273
396
  if (fileDiscovery.shouldGitIgnoreFile(pathName)) {
274
397
  ignoredPaths.push(pathName);
@@ -288,23 +411,23 @@ class GeminiAgent {
288
411
  currentPathSpec = pathName.endsWith('/')
289
412
  ? `${pathName}**`
290
413
  : `${pathName}/**`;
291
- this.#debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
414
+ this.debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
292
415
  }
293
416
  else {
294
- this.#debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
417
+ this.debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
295
418
  }
296
419
  resolvedSuccessfully = true;
297
420
  }
298
421
  else {
299
- this.#debug(`Path ${pathName} is outside the project directory. Skipping.`);
422
+ this.debug(`Path ${pathName} is outside the project directory. Skipping.`);
300
423
  }
301
424
  }
302
425
  catch (error) {
303
426
  if (isNodeError(error) && error.code === 'ENOENT') {
304
427
  if (this.config.getEnableRecursiveFileSearch() && globTool) {
305
- this.#debug(`Path ${pathName} not found directly, attempting glob search.`);
428
+ this.debug(`Path ${pathName} not found directly, attempting glob search.`);
306
429
  try {
307
- const globResult = await globTool.execute({
430
+ const globResult = await globTool.buildAndExecute({
308
431
  pattern: `**/*${pathName}*`,
309
432
  path: this.config.getTargetDir(),
310
433
  }, abortSignal);
@@ -316,15 +439,15 @@ class GeminiAgent {
316
439
  if (lines.length > 1 && lines[1]) {
317
440
  const firstMatchAbsolute = lines[1].trim();
318
441
  currentPathSpec = path.relative(this.config.getTargetDir(), firstMatchAbsolute);
319
- this.#debug(`Glob search for ${pathName} found ${firstMatchAbsolute}, using relative path: ${currentPathSpec}`);
442
+ this.debug(`Glob search for ${pathName} found ${firstMatchAbsolute}, using relative path: ${currentPathSpec}`);
320
443
  resolvedSuccessfully = true;
321
444
  }
322
445
  else {
323
- this.#debug(`Glob search for '**/*${pathName}*' did not return a usable path. Path ${pathName} will be skipped.`);
446
+ this.debug(`Glob search for '**/*${pathName}*' did not return a usable path. Path ${pathName} will be skipped.`);
324
447
  }
325
448
  }
326
449
  else {
327
- this.#debug(`Glob search for '**/*${pathName}*' found no files or an error. Path ${pathName} will be skipped.`);
450
+ this.debug(`Glob search for '**/*${pathName}*' found no files or an error. Path ${pathName} will be skipped.`);
328
451
  }
329
452
  }
330
453
  catch (globError) {
@@ -332,7 +455,7 @@ class GeminiAgent {
332
455
  }
333
456
  }
334
457
  else {
335
- this.#debug(`Glob tool not found. Path ${pathName} will be skipped.`);
458
+ this.debug(`Glob tool not found. Path ${pathName} will be skipped.`);
336
459
  }
337
460
  }
338
461
  else {
@@ -347,22 +470,23 @@ class GeminiAgent {
347
470
  }
348
471
  // Construct the initial part of the query for the LLM
349
472
  let initialQueryText = '';
350
- for (let i = 0; i < message.chunks.length; i++) {
351
- const chunk = message.chunks[i];
473
+ for (let i = 0; i < parts.length; i++) {
474
+ const chunk = parts[i];
352
475
  if ('text' in chunk) {
353
476
  initialQueryText += chunk.text;
354
477
  }
355
478
  else {
356
479
  // type === 'atPath'
357
- const resolvedSpec = atPathToResolvedSpecMap.get(chunk.path);
480
+ const resolvedSpec = chunk.fileData && atPathToResolvedSpecMap.get(chunk.fileData.fileUri);
358
481
  if (i > 0 &&
359
482
  initialQueryText.length > 0 &&
360
483
  !initialQueryText.endsWith(' ') &&
361
484
  resolvedSpec) {
362
485
  // Add space if previous part was text and didn't end with space, or if previous was @path
363
- const prevPart = message.chunks[i - 1];
486
+ const prevPart = parts[i - 1];
364
487
  if ('text' in prevPart ||
365
- ('path' in prevPart && atPathToResolvedSpecMap.has(prevPart.path))) {
488
+ ('fileData' in prevPart &&
489
+ atPathToResolvedSpecMap.has(prevPart.fileData.fileUri))) {
366
490
  initialQueryText += ' ';
367
491
  }
368
492
  }
@@ -375,10 +499,12 @@ class GeminiAgent {
375
499
  if (i > 0 &&
376
500
  initialQueryText.length > 0 &&
377
501
  !initialQueryText.endsWith(' ') &&
378
- !chunk.path.startsWith(' ')) {
502
+ !chunk.fileData?.fileUri.startsWith(' ')) {
379
503
  initialQueryText += ' ';
380
504
  }
381
- initialQueryText += `@${chunk.path}`;
505
+ if (chunk.fileData?.fileUri) {
506
+ initialQueryText += `@${chunk.fileData.fileUri}`;
507
+ }
382
508
  }
383
509
  }
384
510
  }
@@ -386,7 +512,7 @@ class GeminiAgent {
386
512
  // Inform user about ignored paths
387
513
  if (ignoredPaths.length > 0) {
388
514
  const ignoreType = respectGitIgnore ? 'git-ignored' : 'custom-ignored';
389
- this.#debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
515
+ this.debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
390
516
  }
391
517
  // Fallback for lone "@" or completely invalid @-commands resulting in empty initialQueryText
392
518
  if (pathSpecsToRead.length === 0) {
@@ -398,20 +524,31 @@ class GeminiAgent {
398
524
  paths: pathSpecsToRead,
399
525
  respectGitIgnore, // Use configuration setting
400
526
  };
401
- const toolCall = await this.client.pushToolCall({
402
- icon: readManyFilesTool.icon,
403
- label: readManyFilesTool.getDescription(toolArgs),
404
- });
527
+ const callId = `${readManyFilesTool.name}-${Date.now()}`;
405
528
  try {
406
- const result = await readManyFilesTool.execute(toolArgs, abortSignal);
529
+ const invocation = readManyFilesTool.build(toolArgs);
530
+ await this.sendUpdate({
531
+ sessionUpdate: 'tool_call',
532
+ toolCallId: callId,
533
+ status: 'in_progress',
534
+ title: invocation.getDescription(),
535
+ content: [],
536
+ locations: invocation.toolLocations(),
537
+ kind: readManyFilesTool.kind,
538
+ });
539
+ const result = await invocation.execute(abortSignal);
407
540
  const content = toToolCallContent(result) || {
408
- type: 'markdown',
409
- markdown: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
541
+ type: 'content',
542
+ content: {
543
+ type: 'text',
544
+ text: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
545
+ },
410
546
  };
411
- await this.client.updateToolCall({
412
- toolCallId: toolCall.id,
413
- status: 'finished',
414
- content,
547
+ await this.sendUpdate({
548
+ sessionUpdate: 'tool_call_update',
549
+ toolCallId: callId,
550
+ status: 'completed',
551
+ content: content ? [content] : [],
415
552
  });
416
553
  if (Array.isArray(result.llmContent)) {
417
554
  const fileContentRegex = /^--- (.*?) ---\n\n([\s\S]*?)\n\n$/;
@@ -446,18 +583,24 @@ class GeminiAgent {
446
583
  return processedQueryParts;
447
584
  }
448
585
  catch (error) {
449
- await this.client.updateToolCall({
450
- toolCallId: toolCall.id,
451
- status: 'error',
452
- content: {
453
- type: 'markdown',
454
- markdown: `Error reading files (${contentLabelsForDisplay.join(', ')}): ${getErrorMessage(error)}`,
455
- },
586
+ await this.sendUpdate({
587
+ sessionUpdate: 'tool_call_update',
588
+ toolCallId: callId,
589
+ status: 'failed',
590
+ content: [
591
+ {
592
+ type: 'content',
593
+ content: {
594
+ type: 'text',
595
+ text: `Error reading files (${contentLabelsForDisplay.join(', ')}): ${getErrorMessage(error)}`,
596
+ },
597
+ },
598
+ ],
456
599
  });
457
600
  throw error;
458
601
  }
459
602
  }
460
- #debug(msg) {
603
+ debug(msg) {
461
604
  if (this.config.getDebugMode()) {
462
605
  console.warn(msg);
463
606
  }
@@ -467,8 +610,8 @@ function toToolCallContent(toolResult) {
467
610
  if (toolResult.returnDisplay) {
468
611
  if (typeof toolResult.returnDisplay === 'string') {
469
612
  return {
470
- type: 'markdown',
471
- markdown: toolResult.returnDisplay,
613
+ type: 'content',
614
+ content: { type: 'text', text: toolResult.returnDisplay },
472
615
  };
473
616
  }
474
617
  else {
@@ -484,54 +627,65 @@ function toToolCallContent(toolResult) {
484
627
  return null;
485
628
  }
486
629
  }
487
- function toAcpToolCallConfirmation(confirmationDetails) {
488
- switch (confirmationDetails.type) {
630
+ const basicPermissionOptions = [
631
+ {
632
+ optionId: ToolConfirmationOutcome.ProceedOnce,
633
+ name: 'Allow',
634
+ kind: 'allow_once',
635
+ },
636
+ {
637
+ optionId: ToolConfirmationOutcome.Cancel,
638
+ name: 'Reject',
639
+ kind: 'reject_once',
640
+ },
641
+ ];
642
+ function toPermissionOptions(confirmation) {
643
+ switch (confirmation.type) {
489
644
  case 'edit':
490
- return { type: 'edit' };
645
+ return [
646
+ {
647
+ optionId: ToolConfirmationOutcome.ProceedAlways,
648
+ name: 'Allow All Edits',
649
+ kind: 'allow_always',
650
+ },
651
+ ...basicPermissionOptions,
652
+ ];
491
653
  case 'exec':
492
- return {
493
- type: 'execute',
494
- rootCommand: confirmationDetails.rootCommand,
495
- command: confirmationDetails.command,
496
- };
654
+ return [
655
+ {
656
+ optionId: ToolConfirmationOutcome.ProceedAlways,
657
+ name: `Always Allow ${confirmation.rootCommand}`,
658
+ kind: 'allow_always',
659
+ },
660
+ ...basicPermissionOptions,
661
+ ];
497
662
  case 'mcp':
498
- return {
499
- type: 'mcp',
500
- serverName: confirmationDetails.serverName,
501
- toolName: confirmationDetails.toolName,
502
- toolDisplayName: confirmationDetails.toolDisplayName,
503
- };
663
+ return [
664
+ {
665
+ optionId: ToolConfirmationOutcome.ProceedAlwaysServer,
666
+ name: `Always Allow ${confirmation.serverName}`,
667
+ kind: 'allow_always',
668
+ },
669
+ {
670
+ optionId: ToolConfirmationOutcome.ProceedAlwaysTool,
671
+ name: `Always Allow ${confirmation.toolName}`,
672
+ kind: 'allow_always',
673
+ },
674
+ ...basicPermissionOptions,
675
+ ];
504
676
  case 'info':
505
- return {
506
- type: 'fetch',
507
- urls: confirmationDetails.urls || [],
508
- description: confirmationDetails.urls?.length
509
- ? null
510
- : confirmationDetails.prompt,
511
- };
512
- default: {
513
- const unreachable = confirmationDetails;
514
- throw new Error(`Unexpected: ${unreachable}`);
515
- }
516
- }
517
- }
518
- function toToolCallOutcome(outcome) {
519
- switch (outcome) {
520
- case 'allow':
521
- return ToolConfirmationOutcome.ProceedOnce;
522
- case 'alwaysAllow':
523
- return ToolConfirmationOutcome.ProceedAlways;
524
- case 'alwaysAllowMcpServer':
525
- return ToolConfirmationOutcome.ProceedAlwaysServer;
526
- case 'alwaysAllowTool':
527
- return ToolConfirmationOutcome.ProceedAlwaysTool;
528
- case 'reject':
529
- case 'cancel':
530
- return ToolConfirmationOutcome.Cancel;
677
+ return [
678
+ {
679
+ optionId: ToolConfirmationOutcome.ProceedAlways,
680
+ name: `Always Allow`,
681
+ kind: 'allow_always',
682
+ },
683
+ ...basicPermissionOptions,
684
+ ];
531
685
  default: {
532
- const unreachable = outcome;
686
+ const unreachable = confirmation;
533
687
  throw new Error(`Unexpected: ${unreachable}`);
534
688
  }
535
689
  }
536
690
  }
537
- //# sourceMappingURL=acpPeer.js.map
691
+ //# sourceMappingURL=zedIntegration.js.map