@vybestack/llxprt-code 0.1.19-gamma → 0.1.20-nightly.250816.90f427f5

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 (168) hide show
  1. package/README.md +9 -0
  2. package/dist/package.json +5 -5
  3. package/dist/src/auth/oauth-manager.d.ts +1 -0
  4. package/dist/src/auth/oauth-manager.js +24 -13
  5. package/dist/src/auth/oauth-manager.js.map +1 -1
  6. package/dist/src/auth/oauth-manager.spec.js +4 -4
  7. package/dist/src/auth/oauth-manager.spec.js.map +1 -1
  8. package/dist/src/commands/mcp/list.js +1 -1
  9. package/dist/src/commands/mcp/list.js.map +1 -1
  10. package/dist/src/config/config.d.ts +2 -1
  11. package/dist/src/config/config.js +183 -25
  12. package/dist/src/config/config.js.map +1 -1
  13. package/dist/src/config/keyBindings.js +4 -0
  14. package/dist/src/config/keyBindings.js.map +1 -1
  15. package/dist/src/config/settingsSchema.d.ts +18 -9
  16. package/dist/src/config/settingsSchema.js +18 -9
  17. package/dist/src/config/settingsSchema.js.map +1 -1
  18. package/dist/src/config/trustedFolders.d.ts +36 -0
  19. package/dist/src/config/trustedFolders.js +112 -0
  20. package/dist/src/config/trustedFolders.js.map +1 -0
  21. package/dist/src/gemini.js +28 -18
  22. package/dist/src/gemini.js.map +1 -1
  23. package/dist/src/generated/git-commit.d.ts +1 -1
  24. package/dist/src/generated/git-commit.js +1 -1
  25. package/dist/src/nonInteractiveCli.js +3 -4
  26. package/dist/src/nonInteractiveCli.js.map +1 -1
  27. package/dist/src/providers/logging/git-stats.js +0 -1
  28. package/dist/src/providers/logging/git-stats.js.map +1 -1
  29. package/dist/src/providers/providerConfigUtils.js +1 -1
  30. package/dist/src/providers/providerConfigUtils.js.map +1 -1
  31. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  32. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  33. package/dist/src/services/todo-continuation/todoContinuationService.d.ts +0 -1
  34. package/dist/src/services/todo-continuation/todoContinuationService.js +2 -1
  35. package/dist/src/services/todo-continuation/todoContinuationService.js.map +1 -1
  36. package/dist/src/ui/App.js +50 -34
  37. package/dist/src/ui/App.js.map +1 -1
  38. package/dist/src/ui/IdeIntegrationNudge.d.ts +7 -4
  39. package/dist/src/ui/IdeIntegrationNudge.js +31 -10
  40. package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
  41. package/dist/src/ui/commands/authCommand.js +16 -8
  42. package/dist/src/ui/commands/authCommand.js.map +1 -1
  43. package/dist/src/ui/commands/directoryCommand.js +2 -4
  44. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  45. package/dist/src/ui/commands/ideCommand.js +11 -8
  46. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  47. package/dist/src/ui/commands/keyCommand.js +1 -1
  48. package/dist/src/ui/commands/keyCommand.js.map +1 -1
  49. package/dist/src/ui/commands/keyfileCommand.js +1 -1
  50. package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
  51. package/dist/src/ui/commands/mcpCommand.js +10 -6
  52. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  53. package/dist/src/ui/commands/setCommand.js +43 -3
  54. package/dist/src/ui/commands/setCommand.js.map +1 -1
  55. package/dist/src/ui/commands/setupGithubCommand.js +5 -16
  56. package/dist/src/ui/commands/setupGithubCommand.js.map +1 -1
  57. package/dist/src/ui/commands/terminalSetupCommand.d.ts +13 -0
  58. package/dist/src/ui/commands/terminalSetupCommand.js +41 -0
  59. package/dist/src/ui/commands/terminalSetupCommand.js.map +1 -0
  60. package/dist/src/ui/commands/types.d.ts +1 -0
  61. package/dist/src/ui/commands/types.js.map +1 -1
  62. package/dist/src/ui/components/AuthDialog.js +56 -29
  63. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  64. package/dist/src/ui/components/AuthInProgress.js +5 -4
  65. package/dist/src/ui/components/AuthInProgress.js.map +1 -1
  66. package/dist/src/ui/components/DebugProfiler.js +5 -4
  67. package/dist/src/ui/components/DebugProfiler.js.map +1 -1
  68. package/dist/src/ui/components/DetailedMessagesDisplay.js +4 -4
  69. package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
  70. package/dist/src/ui/components/EditorSettingsDialog.js +6 -5
  71. package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
  72. package/dist/src/ui/components/ErrorBoundary.js +2 -2
  73. package/dist/src/ui/components/ErrorBoundary.js.map +1 -1
  74. package/dist/src/ui/components/FolderTrustDialog.js +5 -4
  75. package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
  76. package/dist/src/ui/components/InputPrompt.js +7 -1
  77. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  78. package/dist/src/ui/components/LoggingDialog.js +5 -1
  79. package/dist/src/ui/components/LoggingDialog.js.map +1 -1
  80. package/dist/src/ui/components/OAuthCodeDialog.js +12 -14
  81. package/dist/src/ui/components/OAuthCodeDialog.js.map +1 -1
  82. package/dist/src/ui/components/SettingsDialog.js +12 -10
  83. package/dist/src/ui/components/SettingsDialog.js.map +1 -1
  84. package/dist/src/ui/components/ShellConfirmationDialog.js +5 -4
  85. package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
  86. package/dist/src/ui/components/ThemeDialog.js +6 -5
  87. package/dist/src/ui/components/ThemeDialog.js.map +1 -1
  88. package/dist/src/ui/components/TodoPanel.js +2 -2
  89. package/dist/src/ui/components/TodoPanel.js.map +1 -1
  90. package/dist/src/ui/components/messages/InfoMessage.js +1 -1
  91. package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
  92. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +8 -7
  93. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  94. package/dist/src/ui/components/shared/RadioButtonSelect.js +11 -9
  95. package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
  96. package/dist/src/ui/components/shared/text-buffer.d.ts +17 -4
  97. package/dist/src/ui/components/shared/text-buffer.js +256 -80
  98. package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
  99. package/dist/src/ui/components/shared/vim-buffer-actions.js +139 -152
  100. package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -1
  101. package/dist/src/ui/containers/SessionController.js +23 -23
  102. package/dist/src/ui/containers/SessionController.js.map +1 -1
  103. package/dist/src/ui/hooks/atCommandProcessor.js +1 -1
  104. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  105. package/dist/src/ui/hooks/slashCommandProcessor.js +7 -1
  106. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  107. package/dist/src/ui/hooks/useAuthCommand.js +8 -60
  108. package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
  109. package/dist/src/ui/hooks/useAutoAcceptIndicator.js +5 -5
  110. package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
  111. package/dist/src/ui/hooks/useFocus.d.ts +4 -0
  112. package/dist/src/ui/hooks/useFocus.js +4 -4
  113. package/dist/src/ui/hooks/useFocus.js.map +1 -1
  114. package/dist/src/ui/hooks/useFolderTrust.d.ts +3 -2
  115. package/dist/src/ui/hooks/useFolderTrust.js +24 -9
  116. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  117. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -0
  118. package/dist/src/ui/hooks/useGeminiStream.js +126 -40
  119. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  120. package/dist/src/ui/hooks/useKeypress.d.ts +9 -1
  121. package/dist/src/ui/hooks/useKeypress.js +191 -8
  122. package/dist/src/ui/hooks/useKeypress.js.map +1 -1
  123. package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +15 -0
  124. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +20 -0
  125. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +1 -0
  126. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +5 -4
  127. package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
  128. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js +5 -4
  129. package/dist/src/ui/privacy/CloudPaidPrivacyNotice.js.map +1 -1
  130. package/dist/src/ui/privacy/GeminiPrivacyNotice.js +5 -4
  131. package/dist/src/ui/privacy/GeminiPrivacyNotice.js.map +1 -1
  132. package/dist/src/ui/reducers/sessionReducer.js +1 -0
  133. package/dist/src/ui/reducers/sessionReducer.js.map +1 -1
  134. package/dist/src/ui/utils/kittyProtocolDetector.d.ts +13 -0
  135. package/dist/src/ui/utils/kittyProtocolDetector.js +88 -0
  136. package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -0
  137. package/dist/src/ui/utils/platformConstants.d.ts +38 -0
  138. package/dist/src/ui/utils/platformConstants.js +39 -0
  139. package/dist/src/ui/utils/platformConstants.js.map +1 -0
  140. package/dist/src/ui/utils/renderLoopDetector.js +3 -3
  141. package/dist/src/ui/utils/renderLoopDetector.js.map +1 -1
  142. package/dist/src/ui/utils/terminalSetup.d.ts +30 -0
  143. package/dist/src/ui/utils/terminalSetup.js +281 -0
  144. package/dist/src/ui/utils/terminalSetup.js.map +1 -0
  145. package/dist/src/utils/checks.d.ts +19 -0
  146. package/dist/src/utils/checks.js +24 -0
  147. package/dist/src/utils/checks.js.map +1 -0
  148. package/dist/src/utils/privacy/ConversationDataRedactor.d.ts +0 -2
  149. package/dist/src/utils/privacy/ConversationDataRedactor.js +4 -37
  150. package/dist/src/utils/privacy/ConversationDataRedactor.js.map +1 -1
  151. package/dist/src/zed-integration/acp.d.ts +63 -0
  152. package/dist/src/{acp → zed-integration}/acp.js +76 -44
  153. package/dist/src/zed-integration/acp.js.map +1 -0
  154. package/dist/src/zed-integration/schema.d.ts +11679 -0
  155. package/dist/src/zed-integration/schema.js +305 -0
  156. package/dist/src/zed-integration/schema.js.map +1 -0
  157. package/dist/src/zed-integration/zedIntegration.d.ts +10 -0
  158. package/dist/src/{acp/acpPeer.js → zed-integration/zedIntegration.js} +333 -188
  159. package/dist/src/zed-integration/zedIntegration.js.map +1 -0
  160. package/dist/tsconfig.tsbuildinfo +1 -1
  161. package/package.json +5 -5
  162. package/dist/src/acp/acp.d.ts +0 -208
  163. package/dist/src/acp/acp.js.map +0 -1
  164. package/dist/src/acp/acpPeer.d.ts +0 -8
  165. package/dist/src/acp/acpPeer.js.map +0 -1
  166. package/dist/src/ui/utils/errorParsing.d.ts +0 -7
  167. package/dist/src/ui/utils/errorParsing.js +0 -106
  168. 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 '@vybestack/llxprt-code-core';
6
+ import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, MCPServerConfig, } from '@vybestack/llxprt-code-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);
122
+ }
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;
50
135
  }
51
- async cancelSendMessage() {
52
- if (!this.pendingSend) {
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' };
216
+ }
217
+ async sendUpdate(update) {
218
+ const params = {
219
+ sessionId: this.id,
220
+ update,
221
+ };
222
+ await this.client.sessionUpdate(params);
135
223
  }
136
- async #runTool(abortSignal, promptId, fc) {
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,59 +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 = undefined;
171
- try {
172
- const invocation = tool.build(args);
173
- const confirmationDetails = await invocation.shouldConfirmExecute(abortSignal);
174
- if (confirmationDetails) {
175
- let content = null;
176
- if (confirmationDetails.type === 'edit') {
177
- content = {
178
- type: 'diff',
179
- path: confirmationDetails.fileName,
180
- oldText: confirmationDetails.originalContent,
181
- newText: confirmationDetails.newContent,
182
- };
183
- }
184
- const result = await this.client.requestToolCallConfirmation({
185
- label: invocation.getDescription(),
186
- icon: tool.icon,
187
- content,
188
- confirmation: toAcpToolCallConfirmation(confirmationDetails),
189
- locations: invocation.toolLocations(),
258
+ const invocation = tool.build(args);
259
+ const confirmationDetails = await invocation.shouldConfirmExecute(abortSignal);
260
+ if (confirmationDetails) {
261
+ const content = [];
262
+ if (confirmationDetails.type === 'edit') {
263
+ content.push({
264
+ type: 'diff',
265
+ path: confirmationDetails.fileName,
266
+ oldText: confirmationDetails.originalContent,
267
+ newText: confirmationDetails.newContent,
190
268
  });
191
- await confirmationDetails.onConfirm(toToolCallOutcome(result.outcome));
192
- switch (result.outcome) {
193
- case 'reject':
194
- return errorResponse(new Error(`Tool "${fc.name}" not allowed to run by the user.`));
195
- case 'cancel':
196
- return errorResponse(new Error(`Tool "${fc.name}" was canceled by the user.`));
197
- case 'allow':
198
- case 'alwaysAllow':
199
- case 'alwaysAllowMcpServer':
200
- case 'alwaysAllowTool':
201
- break;
202
- default: {
203
- const resultOutcome = result.outcome;
204
- throw new Error(`Unexpected: ${resultOutcome}`);
205
- }
206
- }
207
- toolCallId = result.id;
208
269
  }
209
- else {
210
- const result = await this.client.pushToolCall({
211
- icon: tool.icon,
212
- label: invocation.getDescription(),
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,
213
278
  locations: invocation.toolLocations(),
214
- });
215
- toolCallId = result.id;
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:
291
+ return errorResponse(new Error(`Tool "${fc.name}" was canceled by the user.`));
292
+ case ToolConfirmationOutcome.ProceedOnce:
293
+ case ToolConfirmationOutcome.ProceedAlways:
294
+ case ToolConfirmationOutcome.ProceedAlwaysServer:
295
+ case ToolConfirmationOutcome.ProceedAlwaysTool:
296
+ case ToolConfirmationOutcome.ModifyWithEditor:
297
+ break;
298
+ default: {
299
+ const resultOutcome = outcome;
300
+ throw new Error(`Unexpected: ${resultOutcome}`);
301
+ }
216
302
  }
303
+ }
304
+ else {
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,
313
+ });
314
+ }
315
+ try {
217
316
  const toolResult = await invocation.execute(abortSignal);
218
- const toolCallContent = toToolCallContent(toolResult);
219
- await this.client.updateToolCall({
220
- toolCallId,
221
- status: 'finished',
222
- content: toolCallContent,
317
+ const content = toToolCallContent(toolResult);
318
+ await this.sendUpdate({
319
+ sessionUpdate: 'tool_call_update',
320
+ toolCallId: callId,
321
+ status: 'completed',
322
+ content: content ? [content] : [],
223
323
  });
224
324
  const durationMs = Date.now() - startTime;
225
325
  logToolCall(this.config, {
@@ -235,27 +335,47 @@ class GeminiAgent {
235
335
  }
236
336
  catch (e) {
237
337
  const error = e instanceof Error ? e : new Error(String(e));
238
- if (toolCallId) {
239
- await this.client.updateToolCall({
240
- toolCallId,
241
- status: 'error',
242
- content: { type: 'markdown', markdown: error.message },
243
- });
244
- }
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
+ ],
345
+ });
245
346
  return errorResponse(error);
246
347
  }
247
348
  }
248
- async #resolveUserMessage(message, abortSignal) {
249
- const atPathCommandParts = message.chunks.filter((part) => 'path' in part);
250
- if (atPathCommandParts.length === 0) {
251
- return message.chunks.map((chunk) => {
252
- if ('text' in chunk) {
253
- 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
+ };
254
370
  }
255
- else {
256
- throw new Error('Unexpected chunk type');
371
+ default: {
372
+ throw new Error(`Unexpected chunk type: '${part.type}'`);
257
373
  }
258
- });
374
+ }
375
+ });
376
+ const atPathCommandParts = parts.filter((part) => 'fileData' in part);
377
+ if (atPathCommandParts.length === 0) {
378
+ return parts;
259
379
  }
260
380
  // Get centralized file discovery service
261
381
  const fileDiscovery = this.config.getFileService();
@@ -271,7 +391,7 @@ class GeminiAgent {
271
391
  throw new Error('Error: read_many_files tool not found.');
272
392
  }
273
393
  for (const atPathPart of atPathCommandParts) {
274
- const pathName = atPathPart.path;
394
+ const pathName = atPathPart.fileData.fileUri;
275
395
  // Check if path should be ignored by git
276
396
  if (fileDiscovery.shouldGitIgnoreFile(pathName)) {
277
397
  ignoredPaths.push(pathName);
@@ -291,21 +411,21 @@ class GeminiAgent {
291
411
  currentPathSpec = pathName.endsWith('/')
292
412
  ? `${pathName}**`
293
413
  : `${pathName}/**`;
294
- this.#debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
414
+ this.debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
295
415
  }
296
416
  else {
297
- this.#debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
417
+ this.debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
298
418
  }
299
419
  resolvedSuccessfully = true;
300
420
  }
301
421
  else {
302
- this.#debug(`Path ${pathName} is outside the project directory. Skipping.`);
422
+ this.debug(`Path ${pathName} is outside the project directory. Skipping.`);
303
423
  }
304
424
  }
305
425
  catch (error) {
306
426
  if (isNodeError(error) && error.code === 'ENOENT') {
307
427
  if (this.config.getEnableRecursiveFileSearch() && globTool) {
308
- this.#debug(`Path ${pathName} not found directly, attempting glob search.`);
428
+ this.debug(`Path ${pathName} not found directly, attempting glob search.`);
309
429
  try {
310
430
  const globResult = await globTool.buildAndExecute({
311
431
  pattern: `**/*${pathName}*`,
@@ -319,15 +439,15 @@ class GeminiAgent {
319
439
  if (lines.length > 1 && lines[1]) {
320
440
  const firstMatchAbsolute = lines[1].trim();
321
441
  currentPathSpec = path.relative(this.config.getTargetDir(), firstMatchAbsolute);
322
- 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}`);
323
443
  resolvedSuccessfully = true;
324
444
  }
325
445
  else {
326
- 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.`);
327
447
  }
328
448
  }
329
449
  else {
330
- 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.`);
331
451
  }
332
452
  }
333
453
  catch (globError) {
@@ -335,7 +455,7 @@ class GeminiAgent {
335
455
  }
336
456
  }
337
457
  else {
338
- this.#debug(`Glob tool not found. Path ${pathName} will be skipped.`);
458
+ this.debug(`Glob tool not found. Path ${pathName} will be skipped.`);
339
459
  }
340
460
  }
341
461
  else {
@@ -350,22 +470,23 @@ class GeminiAgent {
350
470
  }
351
471
  // Construct the initial part of the query for the LLM
352
472
  let initialQueryText = '';
353
- for (let i = 0; i < message.chunks.length; i++) {
354
- const chunk = message.chunks[i];
473
+ for (let i = 0; i < parts.length; i++) {
474
+ const chunk = parts[i];
355
475
  if ('text' in chunk) {
356
476
  initialQueryText += chunk.text;
357
477
  }
358
478
  else {
359
479
  // type === 'atPath'
360
- const resolvedSpec = atPathToResolvedSpecMap.get(chunk.path);
480
+ const resolvedSpec = chunk.fileData && atPathToResolvedSpecMap.get(chunk.fileData.fileUri);
361
481
  if (i > 0 &&
362
482
  initialQueryText.length > 0 &&
363
483
  !initialQueryText.endsWith(' ') &&
364
484
  resolvedSpec) {
365
485
  // Add space if previous part was text and didn't end with space, or if previous was @path
366
- const prevPart = message.chunks[i - 1];
486
+ const prevPart = parts[i - 1];
367
487
  if ('text' in prevPart ||
368
- ('path' in prevPart && atPathToResolvedSpecMap.has(prevPart.path))) {
488
+ ('fileData' in prevPart &&
489
+ atPathToResolvedSpecMap.has(prevPart.fileData.fileUri))) {
369
490
  initialQueryText += ' ';
370
491
  }
371
492
  }
@@ -378,10 +499,12 @@ class GeminiAgent {
378
499
  if (i > 0 &&
379
500
  initialQueryText.length > 0 &&
380
501
  !initialQueryText.endsWith(' ') &&
381
- !chunk.path.startsWith(' ')) {
502
+ !chunk.fileData?.fileUri.startsWith(' ')) {
382
503
  initialQueryText += ' ';
383
504
  }
384
- initialQueryText += `@${chunk.path}`;
505
+ if (chunk.fileData?.fileUri) {
506
+ initialQueryText += `@${chunk.fileData.fileUri}`;
507
+ }
385
508
  }
386
509
  }
387
510
  }
@@ -389,7 +512,7 @@ class GeminiAgent {
389
512
  // Inform user about ignored paths
390
513
  if (ignoredPaths.length > 0) {
391
514
  const ignoreType = respectGitIgnore ? 'git-ignored' : 'custom-ignored';
392
- this.#debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
515
+ this.debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
393
516
  }
394
517
  // Fallback for lone "@" or completely invalid @-commands resulting in empty initialQueryText
395
518
  if (pathSpecsToRead.length === 0) {
@@ -401,23 +524,31 @@ class GeminiAgent {
401
524
  paths: pathSpecsToRead,
402
525
  respectGitIgnore, // Use configuration setting
403
526
  };
404
- let toolCallId = undefined;
527
+ const callId = `${readManyFilesTool.name}-${Date.now()}`;
405
528
  try {
406
529
  const invocation = readManyFilesTool.build(toolArgs);
407
- const toolCall = await this.client.pushToolCall({
408
- icon: readManyFilesTool.icon,
409
- label: invocation.getDescription(),
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,
410
538
  });
411
- toolCallId = toolCall.id;
412
539
  const result = await invocation.execute(abortSignal);
413
540
  const content = toToolCallContent(result) || {
414
- type: 'markdown',
415
- markdown: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
541
+ type: 'content',
542
+ content: {
543
+ type: 'text',
544
+ text: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
545
+ },
416
546
  };
417
- await this.client.updateToolCall({
418
- toolCallId: toolCall.id,
419
- status: 'finished',
420
- content,
547
+ await this.sendUpdate({
548
+ sessionUpdate: 'tool_call_update',
549
+ toolCallId: callId,
550
+ status: 'completed',
551
+ content: content ? [content] : [],
421
552
  });
422
553
  if (Array.isArray(result.llmContent)) {
423
554
  const fileContentRegex = /^--- (.*?) ---\n\n([\s\S]*?)\n\n$/;
@@ -452,20 +583,24 @@ class GeminiAgent {
452
583
  return processedQueryParts;
453
584
  }
454
585
  catch (error) {
455
- if (toolCallId) {
456
- await this.client.updateToolCall({
457
- toolCallId,
458
- status: 'error',
459
- content: {
460
- type: 'markdown',
461
- markdown: `Error reading files (${contentLabelsForDisplay.join(', ')}): ${getErrorMessage(error)}`,
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
+ },
462
597
  },
463
- });
464
- }
598
+ ],
599
+ });
465
600
  throw error;
466
601
  }
467
602
  }
468
- #debug(msg) {
603
+ debug(msg) {
469
604
  if (this.config.getDebugMode()) {
470
605
  console.warn(msg);
471
606
  }
@@ -475,8 +610,8 @@ function toToolCallContent(toolResult) {
475
610
  if (toolResult.returnDisplay) {
476
611
  if (typeof toolResult.returnDisplay === 'string') {
477
612
  return {
478
- type: 'markdown',
479
- markdown: toolResult.returnDisplay,
613
+ type: 'content',
614
+ content: { type: 'text', text: toolResult.returnDisplay },
480
615
  };
481
616
  }
482
617
  else {
@@ -492,55 +627,65 @@ function toToolCallContent(toolResult) {
492
627
  return null;
493
628
  }
494
629
  }
495
- function toAcpToolCallConfirmation(confirmationDetails) {
496
- 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) {
497
644
  case 'edit':
498
- return { type: 'edit' };
645
+ return [
646
+ {
647
+ optionId: ToolConfirmationOutcome.ProceedAlways,
648
+ name: 'Allow All Edits',
649
+ kind: 'allow_always',
650
+ },
651
+ ...basicPermissionOptions,
652
+ ];
499
653
  case 'exec':
500
- return {
501
- type: 'execute',
502
- rootCommand: confirmationDetails.rootCommand,
503
- command: confirmationDetails.command,
504
- };
654
+ return [
655
+ {
656
+ optionId: ToolConfirmationOutcome.ProceedAlways,
657
+ name: `Always Allow ${confirmation.rootCommand}`,
658
+ kind: 'allow_always',
659
+ },
660
+ ...basicPermissionOptions,
661
+ ];
505
662
  case 'mcp':
506
- return {
507
- type: 'mcp',
508
- serverName: confirmationDetails.serverName,
509
- toolName: confirmationDetails.toolName,
510
- toolDisplayName: confirmationDetails.toolDisplayName,
511
- };
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
+ ];
512
676
  case 'info':
513
- return {
514
- type: 'fetch',
515
- urls: confirmationDetails.urls || [],
516
- description: confirmationDetails.urls?.length
517
- ? null
518
- : confirmationDetails.prompt,
519
- };
520
- default: {
521
- // Type exhaustiveness check - if this errors, a new type was added
522
- const unreachable = confirmationDetails;
523
- throw new Error(`Unexpected: ${unreachable}`);
524
- }
525
- }
526
- }
527
- function toToolCallOutcome(outcome) {
528
- switch (outcome) {
529
- case 'allow':
530
- return ToolConfirmationOutcome.ProceedOnce;
531
- case 'alwaysAllow':
532
- return ToolConfirmationOutcome.ProceedAlways;
533
- case 'alwaysAllowMcpServer':
534
- return ToolConfirmationOutcome.ProceedAlwaysServer;
535
- case 'alwaysAllowTool':
536
- return ToolConfirmationOutcome.ProceedAlwaysTool;
537
- case 'reject':
538
- case 'cancel':
539
- return ToolConfirmationOutcome.Cancel;
677
+ return [
678
+ {
679
+ optionId: ToolConfirmationOutcome.ProceedAlways,
680
+ name: `Always Allow`,
681
+ kind: 'allow_always',
682
+ },
683
+ ...basicPermissionOptions,
684
+ ];
540
685
  default: {
541
- const unreachable = outcome;
686
+ const unreachable = confirmation;
542
687
  throw new Error(`Unexpected: ${unreachable}`);
543
688
  }
544
689
  }
545
690
  }
546
- //# sourceMappingURL=acpPeer.js.map
691
+ //# sourceMappingURL=zedIntegration.js.map