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

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 (79) hide show
  1. package/README.md +1 -1
  2. package/dist/package.json +3 -3
  3. package/dist/src/acp/acp.d.ts +208 -0
  4. package/dist/src/{zed-integration → acp}/acp.js +44 -76
  5. package/dist/src/acp/acp.js.map +1 -0
  6. package/dist/src/acp/acpPeer.d.ts +8 -0
  7. package/dist/src/{zed-integration/zedIntegration.js → acp/acpPeer.js} +187 -333
  8. package/dist/src/acp/acpPeer.js.map +1 -0
  9. package/dist/src/config/config.d.ts +1 -1
  10. package/dist/src/config/config.js +8 -11
  11. package/dist/src/config/config.js.map +1 -1
  12. package/dist/src/config/keyBindings.js +0 -4
  13. package/dist/src/config/keyBindings.js.map +1 -1
  14. package/dist/src/gemini.js +3 -6
  15. package/dist/src/gemini.js.map +1 -1
  16. package/dist/src/generated/git-commit.d.ts +1 -1
  17. package/dist/src/generated/git-commit.js +1 -1
  18. package/dist/src/nonInteractiveCli.js +2 -1
  19. package/dist/src/nonInteractiveCli.js.map +1 -1
  20. package/dist/src/services/BuiltinCommandLoader.js +0 -2
  21. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  22. package/dist/src/ui/App.js +2 -8
  23. package/dist/src/ui/App.js.map +1 -1
  24. package/dist/src/ui/commands/directoryCommand.js +4 -2
  25. package/dist/src/ui/commands/directoryCommand.js.map +1 -1
  26. package/dist/src/ui/commands/mcpCommand.js +0 -4
  27. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  28. package/dist/src/ui/commands/types.d.ts +0 -1
  29. package/dist/src/ui/commands/types.js.map +1 -1
  30. package/dist/src/ui/components/InputPrompt.js +1 -7
  31. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  32. package/dist/src/ui/components/shared/vim-buffer-actions.js +1 -2
  33. package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -1
  34. package/dist/src/ui/hooks/slashCommandProcessor.js +46 -67
  35. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  36. package/dist/src/ui/hooks/useFocus.d.ts +0 -4
  37. package/dist/src/ui/hooks/useFocus.js +4 -4
  38. package/dist/src/ui/hooks/useFocus.js.map +1 -1
  39. package/dist/src/ui/hooks/useFolderTrust.d.ts +2 -3
  40. package/dist/src/ui/hooks/useFolderTrust.js +9 -24
  41. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -1
  42. package/dist/src/ui/hooks/useGeminiStream.js +2 -1
  43. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  44. package/dist/src/ui/hooks/useKeypress.d.ts +1 -9
  45. package/dist/src/ui/hooks/useKeypress.js +8 -197
  46. package/dist/src/ui/hooks/useKeypress.js.map +1 -1
  47. package/dist/src/ui/utils/errorParsing.d.ts +7 -0
  48. package/dist/src/ui/utils/errorParsing.js +90 -0
  49. package/dist/src/ui/utils/errorParsing.js.map +1 -0
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +4 -4
  52. package/dist/src/config/trustedFolders.d.ts +0 -36
  53. package/dist/src/config/trustedFolders.js +0 -112
  54. package/dist/src/config/trustedFolders.js.map +0 -1
  55. package/dist/src/ui/commands/terminalSetupCommand.d.ts +0 -13
  56. package/dist/src/ui/commands/terminalSetupCommand.js +0 -41
  57. package/dist/src/ui/commands/terminalSetupCommand.js.map +0 -1
  58. package/dist/src/ui/hooks/useKittyKeyboardProtocol.d.ts +0 -15
  59. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js +0 -20
  60. package/dist/src/ui/hooks/useKittyKeyboardProtocol.js.map +0 -1
  61. package/dist/src/ui/utils/kittyProtocolDetector.d.ts +0 -13
  62. package/dist/src/ui/utils/kittyProtocolDetector.js +0 -88
  63. package/dist/src/ui/utils/kittyProtocolDetector.js.map +0 -1
  64. package/dist/src/ui/utils/platformConstants.d.ts +0 -38
  65. package/dist/src/ui/utils/platformConstants.js +0 -39
  66. package/dist/src/ui/utils/platformConstants.js.map +0 -1
  67. package/dist/src/ui/utils/terminalSetup.d.ts +0 -30
  68. package/dist/src/ui/utils/terminalSetup.js +0 -281
  69. package/dist/src/ui/utils/terminalSetup.js.map +0 -1
  70. package/dist/src/utils/checks.d.ts +0 -19
  71. package/dist/src/utils/checks.js +0 -24
  72. package/dist/src/utils/checks.js.map +0 -1
  73. package/dist/src/zed-integration/acp.d.ts +0 -63
  74. package/dist/src/zed-integration/acp.js.map +0 -1
  75. package/dist/src/zed-integration/schema.d.ts +0 -11679
  76. package/dist/src/zed-integration/schema.js +0 -305
  77. package/dist/src/zed-integration/schema.js.map +0 -1
  78. package/dist/src/zed-integration/zedIntegration.d.ts +0 -10
  79. package/dist/src/zed-integration/zedIntegration.js.map +0 -1
@@ -3,16 +3,13 @@
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, MCPServerConfig, } from '@google/gemini-cli-core';
6
+ import { AuthType, logToolCall, convertToFunctionResponse, ToolConfirmationOutcome, clearCachedCredentialFile, isNodeError, getErrorMessage, isWithinRoot, getErrorStatus, } 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
- 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) {
12
+ export async function runAcpPeer(config, settings) {
16
13
  const stdout = Writable.toWeb(process.stdout);
17
14
  const stdin = Readable.toWeb(process.stdin);
18
15
  // Stdout is used to send messages to the client, so console.log/console.info
@@ -20,138 +17,61 @@ export async function runZedIntegration(config, settings, extensions, argv) {
20
17
  console.log = console.error;
21
18
  console.info = console.error;
22
19
  console.debug = console.error;
23
- new acp.AgentSideConnection((client) => new GeminiAgent(config, settings, extensions, argv, client), stdout, stdin);
20
+ new acp.ClientConnection((client) => new GeminiAgent(config, settings, client), stdout, stdin);
24
21
  }
25
22
  class GeminiAgent {
26
23
  config;
27
24
  settings;
28
- extensions;
29
- argv;
30
25
  client;
31
- sessions = new Map();
32
- constructor(config, settings, extensions, argv, client) {
26
+ chat;
27
+ pendingSend;
28
+ constructor(config, settings, client) {
33
29
  this.config = config;
34
30
  this.settings = settings;
35
- this.extensions = extensions;
36
- this.argv = argv;
37
31
  this.client = client;
38
32
  }
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);
33
+ async initialize(_) {
74
34
  let isAuthenticated = false;
75
35
  if (this.settings.merged.selectedAuthType) {
76
36
  try {
77
- await config.refreshAuth(this.settings.merged.selectedAuthType);
37
+ await this.config.refreshAuth(this.settings.merged.selectedAuthType);
78
38
  isAuthenticated = true;
79
39
  }
80
- catch (e) {
81
- console.error(`Authentication failed: ${e}`);
82
- }
83
- }
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
- };
94
- }
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;
40
+ catch (error) {
41
+ console.error('Failed to refresh auth:', error);
101
42
  }
102
- mergedMcpServers[name] = new MCPServerConfig(command, args, env, cwd);
103
43
  }
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;
44
+ return { protocolVersion: acp.LATEST_PROTOCOL_VERSION, isAuthenticated };
108
45
  }
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;
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);
135
50
  }
136
- async cancelPendingPrompt() {
137
- if (!this.pendingPrompt) {
51
+ async cancelSendMessage() {
52
+ if (!this.pendingSend) {
138
53
  throw new Error('Not currently generating');
139
54
  }
140
- this.pendingPrompt.abort();
141
- this.pendingPrompt = null;
55
+ this.pendingSend.abort();
56
+ delete this.pendingSend;
142
57
  }
143
- async prompt(params) {
144
- this.pendingPrompt?.abort();
58
+ async sendUserMessage(params) {
59
+ this.pendingSend?.abort();
145
60
  const pendingSend = new AbortController();
146
- this.pendingPrompt = pendingSend;
61
+ this.pendingSend = pendingSend;
62
+ if (!this.chat) {
63
+ const geminiClient = this.config.getGeminiClient();
64
+ this.chat = await geminiClient.startChat();
65
+ }
147
66
  const promptId = Math.random().toString(16).slice(2);
148
67
  const chat = this.chat;
149
- const parts = await this.#resolvePrompt(params.prompt, pendingSend.signal);
68
+ const toolRegistry = await this.config.getToolRegistry();
69
+ const parts = await this.#resolveUserMessage(params, pendingSend.signal);
150
70
  let nextMessage = { role: 'user', parts };
151
71
  while (nextMessage !== null) {
152
72
  if (pendingSend.signal.aborted) {
153
73
  chat.addHistory(nextMessage);
154
- return { stopReason: 'cancelled' };
74
+ return;
155
75
  }
156
76
  const functionCalls = [];
157
77
  try {
@@ -159,12 +79,17 @@ class Session {
159
79
  message: nextMessage?.parts ?? [],
160
80
  config: {
161
81
  abortSignal: pendingSend.signal,
82
+ tools: [
83
+ {
84
+ functionDeclarations: toolRegistry.getFunctionDeclarations(),
85
+ },
86
+ ],
162
87
  },
163
88
  }, promptId);
164
89
  nextMessage = null;
165
90
  for await (const resp of responseStream) {
166
91
  if (pendingSend.signal.aborted) {
167
- return { stopReason: 'cancelled' };
92
+ return;
168
93
  }
169
94
  if (resp.candidates && resp.candidates.length > 0) {
170
95
  const candidate = resp.candidates[0];
@@ -172,15 +97,10 @@ class Session {
172
97
  if (!part.text) {
173
98
  continue;
174
99
  }
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,
100
+ this.client.streamAssistantMessageChunk({
101
+ chunk: part.thought
102
+ ? { thought: part.text }
103
+ : { text: part.text },
184
104
  });
185
105
  }
186
106
  }
@@ -198,7 +118,7 @@ class Session {
198
118
  if (functionCalls.length > 0) {
199
119
  const toolResponseParts = [];
200
120
  for (const fc of functionCalls) {
201
- const response = await this.runTool(pendingSend.signal, promptId, fc);
121
+ const response = await this.#runTool(pendingSend.signal, promptId, fc);
202
122
  const parts = Array.isArray(response) ? response : [response];
203
123
  for (const part of parts) {
204
124
  if (typeof part === 'string') {
@@ -212,16 +132,8 @@ class Session {
212
132
  nextMessage = { role: 'user', parts: toolResponseParts };
213
133
  }
214
134
  }
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);
223
135
  }
224
- async runTool(abortSignal, promptId, fc) {
136
+ async #runTool(abortSignal, promptId, fc) {
225
137
  const callId = fc.id ?? `${fc.name}-${Date.now()}`;
226
138
  const args = (fc.args ?? {});
227
139
  const startTime = Date.now();
@@ -255,71 +167,59 @@ class Session {
255
167
  if (!tool) {
256
168
  return errorResponse(new Error(`Tool "${fc.name}" not found in registry.`));
257
169
  }
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,
268
- });
269
- }
270
- const params = {
271
- sessionId: this.id,
272
- options: toPermissionOptions(confirmationDetails),
273
- toolCall: {
274
- toolCallId: callId,
275
- status: 'pending',
276
- title: invocation.getDescription(),
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,
277
187
  content,
188
+ confirmation: toAcpToolCallConfirmation(confirmationDetails),
278
189
  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:
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}`);
190
+ });
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
+ }
301
206
  }
207
+ toolCallId = result.id;
208
+ }
209
+ else {
210
+ const result = await this.client.pushToolCall({
211
+ icon: tool.icon,
212
+ label: invocation.getDescription(),
213
+ locations: invocation.toolLocations(),
214
+ });
215
+ toolCallId = result.id;
302
216
  }
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 {
316
217
  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] : [],
218
+ const toolCallContent = toToolCallContent(toolResult);
219
+ await this.client.updateToolCall({
220
+ toolCallId,
221
+ status: 'finished',
222
+ content: toolCallContent,
323
223
  });
324
224
  const durationMs = Date.now() - startTime;
325
225
  logToolCall(this.config, {
@@ -335,47 +235,27 @@ class Session {
335
235
  }
336
236
  catch (e) {
337
237
  const error = e instanceof Error ? e : new Error(String(e));
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
- });
238
+ if (toolCallId) {
239
+ await this.client.updateToolCall({
240
+ toolCallId,
241
+ status: 'error',
242
+ content: { type: 'markdown', markdown: error.message },
243
+ });
244
+ }
346
245
  return errorResponse(error);
347
246
  }
348
247
  }
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
- };
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 };
370
254
  }
371
- default: {
372
- throw new Error(`Unexpected chunk type: '${part.type}'`);
255
+ else {
256
+ throw new Error('Unexpected chunk type');
373
257
  }
374
- }
375
- });
376
- const atPathCommandParts = parts.filter((part) => 'fileData' in part);
377
- if (atPathCommandParts.length === 0) {
378
- return parts;
258
+ });
379
259
  }
380
260
  // Get centralized file discovery service
381
261
  const fileDiscovery = this.config.getFileService();
@@ -391,7 +271,7 @@ class Session {
391
271
  throw new Error('Error: read_many_files tool not found.');
392
272
  }
393
273
  for (const atPathPart of atPathCommandParts) {
394
- const pathName = atPathPart.fileData.fileUri;
274
+ const pathName = atPathPart.path;
395
275
  // Check if path should be ignored by git
396
276
  if (fileDiscovery.shouldGitIgnoreFile(pathName)) {
397
277
  ignoredPaths.push(pathName);
@@ -411,21 +291,21 @@ class Session {
411
291
  currentPathSpec = pathName.endsWith('/')
412
292
  ? `${pathName}**`
413
293
  : `${pathName}/**`;
414
- this.debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
294
+ this.#debug(`Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`);
415
295
  }
416
296
  else {
417
- this.debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
297
+ this.#debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
418
298
  }
419
299
  resolvedSuccessfully = true;
420
300
  }
421
301
  else {
422
- this.debug(`Path ${pathName} is outside the project directory. Skipping.`);
302
+ this.#debug(`Path ${pathName} is outside the project directory. Skipping.`);
423
303
  }
424
304
  }
425
305
  catch (error) {
426
306
  if (isNodeError(error) && error.code === 'ENOENT') {
427
307
  if (this.config.getEnableRecursiveFileSearch() && globTool) {
428
- this.debug(`Path ${pathName} not found directly, attempting glob search.`);
308
+ this.#debug(`Path ${pathName} not found directly, attempting glob search.`);
429
309
  try {
430
310
  const globResult = await globTool.buildAndExecute({
431
311
  pattern: `**/*${pathName}*`,
@@ -439,15 +319,15 @@ class Session {
439
319
  if (lines.length > 1 && lines[1]) {
440
320
  const firstMatchAbsolute = lines[1].trim();
441
321
  currentPathSpec = path.relative(this.config.getTargetDir(), firstMatchAbsolute);
442
- this.debug(`Glob search for ${pathName} found ${firstMatchAbsolute}, using relative path: ${currentPathSpec}`);
322
+ this.#debug(`Glob search for ${pathName} found ${firstMatchAbsolute}, using relative path: ${currentPathSpec}`);
443
323
  resolvedSuccessfully = true;
444
324
  }
445
325
  else {
446
- this.debug(`Glob search for '**/*${pathName}*' did not return a usable path. Path ${pathName} will be skipped.`);
326
+ this.#debug(`Glob search for '**/*${pathName}*' did not return a usable path. Path ${pathName} will be skipped.`);
447
327
  }
448
328
  }
449
329
  else {
450
- this.debug(`Glob search for '**/*${pathName}*' found no files or an error. Path ${pathName} will be skipped.`);
330
+ this.#debug(`Glob search for '**/*${pathName}*' found no files or an error. Path ${pathName} will be skipped.`);
451
331
  }
452
332
  }
453
333
  catch (globError) {
@@ -455,7 +335,7 @@ class Session {
455
335
  }
456
336
  }
457
337
  else {
458
- this.debug(`Glob tool not found. Path ${pathName} will be skipped.`);
338
+ this.#debug(`Glob tool not found. Path ${pathName} will be skipped.`);
459
339
  }
460
340
  }
461
341
  else {
@@ -470,23 +350,22 @@ class Session {
470
350
  }
471
351
  // Construct the initial part of the query for the LLM
472
352
  let initialQueryText = '';
473
- for (let i = 0; i < parts.length; i++) {
474
- const chunk = parts[i];
353
+ for (let i = 0; i < message.chunks.length; i++) {
354
+ const chunk = message.chunks[i];
475
355
  if ('text' in chunk) {
476
356
  initialQueryText += chunk.text;
477
357
  }
478
358
  else {
479
359
  // type === 'atPath'
480
- const resolvedSpec = chunk.fileData && atPathToResolvedSpecMap.get(chunk.fileData.fileUri);
360
+ const resolvedSpec = atPathToResolvedSpecMap.get(chunk.path);
481
361
  if (i > 0 &&
482
362
  initialQueryText.length > 0 &&
483
363
  !initialQueryText.endsWith(' ') &&
484
364
  resolvedSpec) {
485
365
  // Add space if previous part was text and didn't end with space, or if previous was @path
486
- const prevPart = parts[i - 1];
366
+ const prevPart = message.chunks[i - 1];
487
367
  if ('text' in prevPart ||
488
- ('fileData' in prevPart &&
489
- atPathToResolvedSpecMap.has(prevPart.fileData.fileUri))) {
368
+ ('path' in prevPart && atPathToResolvedSpecMap.has(prevPart.path))) {
490
369
  initialQueryText += ' ';
491
370
  }
492
371
  }
@@ -499,12 +378,10 @@ class Session {
499
378
  if (i > 0 &&
500
379
  initialQueryText.length > 0 &&
501
380
  !initialQueryText.endsWith(' ') &&
502
- !chunk.fileData?.fileUri.startsWith(' ')) {
381
+ !chunk.path.startsWith(' ')) {
503
382
  initialQueryText += ' ';
504
383
  }
505
- if (chunk.fileData?.fileUri) {
506
- initialQueryText += `@${chunk.fileData.fileUri}`;
507
- }
384
+ initialQueryText += `@${chunk.path}`;
508
385
  }
509
386
  }
510
387
  }
@@ -512,7 +389,7 @@ class Session {
512
389
  // Inform user about ignored paths
513
390
  if (ignoredPaths.length > 0) {
514
391
  const ignoreType = respectGitIgnore ? 'git-ignored' : 'custom-ignored';
515
- this.debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
392
+ this.#debug(`Ignored ${ignoredPaths.length} ${ignoreType} files: ${ignoredPaths.join(', ')}`);
516
393
  }
517
394
  // Fallback for lone "@" or completely invalid @-commands resulting in empty initialQueryText
518
395
  if (pathSpecsToRead.length === 0) {
@@ -524,31 +401,23 @@ class Session {
524
401
  paths: pathSpecsToRead,
525
402
  respectGitIgnore, // Use configuration setting
526
403
  };
527
- const callId = `${readManyFilesTool.name}-${Date.now()}`;
404
+ let toolCallId = undefined;
528
405
  try {
529
406
  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,
407
+ const toolCall = await this.client.pushToolCall({
408
+ icon: readManyFilesTool.icon,
409
+ label: invocation.getDescription(),
538
410
  });
411
+ toolCallId = toolCall.id;
539
412
  const result = await invocation.execute(abortSignal);
540
413
  const content = toToolCallContent(result) || {
541
- type: 'content',
542
- content: {
543
- type: 'text',
544
- text: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
545
- },
414
+ type: 'markdown',
415
+ markdown: `Successfully read: ${contentLabelsForDisplay.join(', ')}`,
546
416
  };
547
- await this.sendUpdate({
548
- sessionUpdate: 'tool_call_update',
549
- toolCallId: callId,
550
- status: 'completed',
551
- content: content ? [content] : [],
417
+ await this.client.updateToolCall({
418
+ toolCallId: toolCall.id,
419
+ status: 'finished',
420
+ content,
552
421
  });
553
422
  if (Array.isArray(result.llmContent)) {
554
423
  const fileContentRegex = /^--- (.*?) ---\n\n([\s\S]*?)\n\n$/;
@@ -583,24 +452,20 @@ class Session {
583
452
  return processedQueryParts;
584
453
  }
585
454
  catch (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
- },
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)}`,
597
462
  },
598
- ],
599
- });
463
+ });
464
+ }
600
465
  throw error;
601
466
  }
602
467
  }
603
- debug(msg) {
468
+ #debug(msg) {
604
469
  if (this.config.getDebugMode()) {
605
470
  console.warn(msg);
606
471
  }
@@ -610,8 +475,8 @@ function toToolCallContent(toolResult) {
610
475
  if (toolResult.returnDisplay) {
611
476
  if (typeof toolResult.returnDisplay === 'string') {
612
477
  return {
613
- type: 'content',
614
- content: { type: 'text', text: toolResult.returnDisplay },
478
+ type: 'markdown',
479
+ markdown: toolResult.returnDisplay,
615
480
  };
616
481
  }
617
482
  else {
@@ -627,65 +492,54 @@ function toToolCallContent(toolResult) {
627
492
  return null;
628
493
  }
629
494
  }
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) {
495
+ function toAcpToolCallConfirmation(confirmationDetails) {
496
+ switch (confirmationDetails.type) {
644
497
  case 'edit':
645
- return [
646
- {
647
- optionId: ToolConfirmationOutcome.ProceedAlways,
648
- name: 'Allow All Edits',
649
- kind: 'allow_always',
650
- },
651
- ...basicPermissionOptions,
652
- ];
498
+ return { type: 'edit' };
653
499
  case 'exec':
654
- return [
655
- {
656
- optionId: ToolConfirmationOutcome.ProceedAlways,
657
- name: `Always Allow ${confirmation.rootCommand}`,
658
- kind: 'allow_always',
659
- },
660
- ...basicPermissionOptions,
661
- ];
500
+ return {
501
+ type: 'execute',
502
+ rootCommand: confirmationDetails.rootCommand,
503
+ command: confirmationDetails.command,
504
+ };
662
505
  case 'mcp':
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
- ];
506
+ return {
507
+ type: 'mcp',
508
+ serverName: confirmationDetails.serverName,
509
+ toolName: confirmationDetails.toolName,
510
+ toolDisplayName: confirmationDetails.toolDisplayName,
511
+ };
676
512
  case 'info':
677
- return [
678
- {
679
- optionId: ToolConfirmationOutcome.ProceedAlways,
680
- name: `Always Allow`,
681
- kind: 'allow_always',
682
- },
683
- ...basicPermissionOptions,
684
- ];
513
+ return {
514
+ type: 'fetch',
515
+ urls: confirmationDetails.urls || [],
516
+ description: confirmationDetails.urls?.length
517
+ ? null
518
+ : confirmationDetails.prompt,
519
+ };
520
+ default: {
521
+ const unreachable = confirmationDetails;
522
+ throw new Error(`Unexpected: ${unreachable}`);
523
+ }
524
+ }
525
+ }
526
+ function toToolCallOutcome(outcome) {
527
+ switch (outcome) {
528
+ case 'allow':
529
+ return ToolConfirmationOutcome.ProceedOnce;
530
+ case 'alwaysAllow':
531
+ return ToolConfirmationOutcome.ProceedAlways;
532
+ case 'alwaysAllowMcpServer':
533
+ return ToolConfirmationOutcome.ProceedAlwaysServer;
534
+ case 'alwaysAllowTool':
535
+ return ToolConfirmationOutcome.ProceedAlwaysTool;
536
+ case 'reject':
537
+ case 'cancel':
538
+ return ToolConfirmationOutcome.Cancel;
685
539
  default: {
686
- const unreachable = confirmation;
540
+ const unreachable = outcome;
687
541
  throw new Error(`Unexpected: ${unreachable}`);
688
542
  }
689
543
  }
690
544
  }
691
- //# sourceMappingURL=zedIntegration.js.map
545
+ //# sourceMappingURL=acpPeer.js.map