Add version detection for CC (#36502)
- Render a helpful message when the installed CC version is too old - Show the full path for agent binaries when the version is not recent enough (helps in cases where multiple binaries are installed in different places) - Add UI for the case where a server binary is not installed at all - Refresh thread view after installing/updating server binary Release Notes: - N/A
This commit is contained in:
parent
7c7043947b
commit
3996587c0b
8 changed files with 195 additions and 85 deletions
|
@ -37,6 +37,7 @@ paths.workspace = true
|
|||
project.workspace = true
|
||||
rand.workspace = true
|
||||
schemars.workspace = true
|
||||
semver.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
|
|
|
@ -14,7 +14,7 @@ use anyhow::{Context as _, Result};
|
|||
use gpui::{App, AppContext as _, AsyncApp, Entity, Task, WeakEntity};
|
||||
|
||||
use crate::{AgentServerCommand, acp::UnsupportedVersion};
|
||||
use acp_thread::{AcpThread, AgentConnection, AuthRequired};
|
||||
use acp_thread::{AcpThread, AgentConnection, AuthRequired, LoadError};
|
||||
|
||||
pub struct AcpConnection {
|
||||
server_name: &'static str,
|
||||
|
@ -87,7 +87,9 @@ impl AcpConnection {
|
|||
for session in sessions.borrow().values() {
|
||||
session
|
||||
.thread
|
||||
.update(cx, |thread, cx| thread.emit_server_exited(status, cx))
|
||||
.update(cx, |thread, cx| {
|
||||
thread.emit_load_error(LoadError::Exited { status }, cx)
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ use smol::process::Child;
|
|||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use util::command::new_smol_command;
|
||||
use uuid::Uuid;
|
||||
|
||||
use agent_client_protocol as acp;
|
||||
|
@ -36,7 +37,7 @@ use util::{ResultExt, debug_panic};
|
|||
use crate::claude::mcp_server::{ClaudeZedMcpServer, McpConfig};
|
||||
use crate::claude::tools::ClaudeTool;
|
||||
use crate::{AgentServer, AgentServerCommand, AllAgentServersSettings};
|
||||
use acp_thread::{AcpThread, AgentConnection, AuthRequired, MentionUri};
|
||||
use acp_thread::{AcpThread, AgentConnection, AuthRequired, LoadError, MentionUri};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClaudeCode;
|
||||
|
@ -103,7 +104,11 @@ impl AgentConnection for ClaudeAgentConnection {
|
|||
)
|
||||
.await
|
||||
else {
|
||||
anyhow::bail!("Failed to find claude binary");
|
||||
return Err(LoadError::NotInstalled {
|
||||
error_message: "Failed to find Claude Code binary".into(),
|
||||
install_message: "Install Claude Code".into(),
|
||||
install_command: "npm install -g @anthropic-ai/claude-code@latest".into(),
|
||||
}.into());
|
||||
};
|
||||
|
||||
let api_key =
|
||||
|
@ -211,9 +216,32 @@ impl AgentConnection for ClaudeAgentConnection {
|
|||
if let Some(status) = child.status().await.log_err()
|
||||
&& let Some(thread) = thread_rx.recv().await.ok()
|
||||
{
|
||||
let version = claude_version(command.path.clone(), cx).await.log_err();
|
||||
let help = claude_help(command.path.clone(), cx).await.log_err();
|
||||
thread
|
||||
.update(cx, |thread, cx| {
|
||||
thread.emit_server_exited(status, cx);
|
||||
let error = if let Some(version) = version
|
||||
&& let Some(help) = help
|
||||
&& (!help.contains("--input-format")
|
||||
|| !help.contains("--session-id"))
|
||||
{
|
||||
LoadError::Unsupported {
|
||||
error_message: format!(
|
||||
"Your installed version of Claude Code ({}, version {}) does not have required features for use with Zed.",
|
||||
command.path.to_string_lossy(),
|
||||
version,
|
||||
)
|
||||
.into(),
|
||||
upgrade_message: "Upgrade Claude Code to latest".into(),
|
||||
upgrade_command: format!(
|
||||
"{} update",
|
||||
command.path.to_string_lossy()
|
||||
),
|
||||
}
|
||||
} else {
|
||||
LoadError::Exited { status }
|
||||
};
|
||||
thread.emit_load_error(error, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
@ -383,6 +411,27 @@ fn spawn_claude(
|
|||
Ok(child)
|
||||
}
|
||||
|
||||
fn claude_version(path: PathBuf, cx: &mut AsyncApp) -> Task<Result<semver::Version>> {
|
||||
cx.background_spawn(async move {
|
||||
let output = new_smol_command(path).arg("--version").output().await?;
|
||||
let output = String::from_utf8(output.stdout)?;
|
||||
let version = output
|
||||
.trim()
|
||||
.strip_suffix(" (Claude Code)")
|
||||
.context("parsing Claude version")?;
|
||||
let version = semver::Version::parse(version)?;
|
||||
anyhow::Ok(version)
|
||||
})
|
||||
}
|
||||
|
||||
fn claude_help(path: PathBuf, cx: &mut AsyncApp) -> Task<Result<String>> {
|
||||
cx.background_spawn(async move {
|
||||
let output = new_smol_command(path).arg("--help").output().await?;
|
||||
let output = String::from_utf8(output.stdout)?;
|
||||
anyhow::Ok(output)
|
||||
})
|
||||
}
|
||||
|
||||
struct ClaudeAgentSession {
|
||||
outgoing_tx: UnboundedSender<SdkMessage>,
|
||||
turn_state: Rc<RefCell<TurnState>>,
|
||||
|
|
|
@ -50,7 +50,11 @@ impl AgentServer for Gemini {
|
|||
let Some(command) =
|
||||
AgentServerCommand::resolve("gemini", &[ACP_ARG], None, settings, &project, cx).await
|
||||
else {
|
||||
anyhow::bail!("Failed to find gemini binary");
|
||||
return Err(LoadError::NotInstalled {
|
||||
error_message: "Failed to find Gemini CLI binary".into(),
|
||||
install_message: "Install Gemini CLI".into(),
|
||||
install_command: "npm install -g @google/gemini-cli@latest".into()
|
||||
}.into());
|
||||
};
|
||||
|
||||
let result = crate::acp::connect(server_name, command.clone(), &root_dir, cx).await;
|
||||
|
@ -75,10 +79,11 @@ impl AgentServer for Gemini {
|
|||
if !supported {
|
||||
return Err(LoadError::Unsupported {
|
||||
error_message: format!(
|
||||
"Your installed version of Gemini {} doesn't support the Agentic Coding Protocol (ACP).",
|
||||
"Your installed version of Gemini CLI ({}, version {}) doesn't support the Agentic Coding Protocol (ACP).",
|
||||
command.path.to_string_lossy(),
|
||||
current_version
|
||||
).into(),
|
||||
upgrade_message: "Upgrade Gemini to Latest".into(),
|
||||
upgrade_message: "Upgrade Gemini CLI to latest".into(),
|
||||
upgrade_command: "npm install -g @google/gemini-cli@latest".into(),
|
||||
}.into())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue