Skip to content

Commit 2d4d34a

Browse files
theahuranori-agent
andauthored
fix(acp): re-apply Claude ACP adapter upgrade to @agentclientprotocol scope (#449)
## Summary 🤖 Generated with [Nori](https://www.npmjs.com/package/nori-ai) - Re-applies the Claude ACP adapter package rename from `@zed-industries/claude-agent-acp` (frozen at 0.23.1) to `@agentclientprotocol/claude-agent-acp` (active, latest 0.30.0) - The original upgrade (PR #447) was reverted in PR #448 due to a "Failed to create ACP session" error - Root cause investigation showed the error was transient — the new adapter v0.30.0 is fully protocol-compatible with our `agent-client-protocol-schema v0.11.6` ## Investigation Details The "Failed to create ACP session" error was traced through the full error chain (`sacp_connection.rs:507` → `spawn_and_relay.rs:59-78` → `agent.rs:273`). Manual protocol testing with v0.30.0 confirmed: - `initialize` handshake succeeds (protocol version V1 negotiation) - `session/new` request succeeds (schema fields `cwd` and `mcpServers` are correct) - `NewSessionResponse` deserializes correctly despite new fields (`modes`, `configOptions`) End-to-end TUI verification with `NORI_MANAGED_BY_NPM=1` (to force npx and the real v0.30.0 adapter) confirmed full round-trip: spawn → handshake → session → prompt → response. ## Test Plan - [x] `test_get_claude_code_config` verifies the built-in Claude config uses the new package name - [x] All 443 passing ACP crate tests still pass (14 pre-existing failures in `backend::tests::part3` are unrelated — they require a mock ACP binary) - [x] End-to-end TUI verification: built nori binary, launched via tmux with real Claude adapter v0.30.0, sent a message and received a response - [x] Clippy clean Share Nori with your team: https://www.npmjs.com/package/nori-skillsets --------- Co-authored-by: Nori <contact@tilework.tech>
1 parent 5a5eba2 commit 2d4d34a

3 files changed

Lines changed: 29 additions & 11 deletions

File tree

nori-rs/acp/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ diffy = { workspace = true }
3838
chrono = { workspace = true }
3939
uuid = { workspace = true, features = ["v4"] }
4040
sha2 = { workspace = true }
41+
which = { workspace = true }
4142

4243
[target.'cfg(unix)'.dependencies]
4344
libc = { workspace = true }

nori-rs/acp/src/config/types/tests.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ name = "Claude Code"
10231023
slug = "claude-code"
10241024
10251025
[agents.distribution.npx]
1026-
package = "@zed-industries/claude-agent-acp"
1026+
package = "@agentclientprotocol/claude-agent-acp"
10271027
"#,
10281028
)
10291029
.unwrap();
@@ -1033,7 +1033,7 @@ package = "@zed-industries/claude-agent-acp"
10331033
assert!(config.agents[0].distribution.npx.is_some());
10341034
assert_eq!(
10351035
config.agents[0].distribution.npx.as_ref().unwrap().package,
1036-
"@zed-industries/claude-agent-acp"
1036+
"@agentclientprotocol/claude-agent-acp"
10371037
);
10381038
}
10391039

@@ -1130,7 +1130,7 @@ name = "Claude Code"
11301130
slug = "claude-code"
11311131
11321132
[agents.distribution.npx]
1133-
package = "@zed-industries/claude-agent-acp"
1133+
package = "@agentclientprotocol/claude-agent-acp"
11341134
11351135
[[agents]]
11361136
name = "Kimi"
@@ -1217,15 +1217,15 @@ fn test_agent_distribution_resolve_rejects_multiple() {
12171217
fn test_agent_distribution_resolve_npx() {
12181218
let dist = AgentDistributionToml {
12191219
npx: Some(PackageDistribution {
1220-
package: "@zed-industries/claude-agent-acp".to_string(),
1220+
package: "@agentclientprotocol/claude-agent-acp".to_string(),
12211221
args: vec![],
12221222
}),
12231223
..Default::default()
12241224
};
12251225
let resolved = dist.resolve().unwrap();
12261226
assert!(matches!(resolved, ResolvedDistribution::Npx { .. }));
12271227
if let ResolvedDistribution::Npx { package, args } = resolved {
1228-
assert_eq!(package, "@zed-industries/claude-agent-acp");
1228+
assert_eq!(package, "@agentclientprotocol/claude-agent-acp");
12291229
assert!(args.is_empty());
12301230
}
12311231
}

nori-rs/acp/src/registry.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ impl AgentKind {
9797
/// Get the ACP adapter package name for launching this agent
9898
pub fn acp_package(&self) -> &'static str {
9999
match self {
100-
// Claude and Codex use Zed's ACP adapters
101-
AgentKind::ClaudeCode => "@zed-industries/claude-agent-acp",
100+
// @latest forces bunx to resolve the new scope instead of a stale
101+
// @zed-industries cache entry with the same unscoped package name.
102+
AgentKind::ClaudeCode => "@agentclientprotocol/claude-agent-acp@latest",
103+
// Codex uses Zed's ACP adapter
102104
AgentKind::Codex => "@zed-industries/codex-acp",
103105
// Gemini has native ACP support
104106
AgentKind::Gemini => "@google/gemini-cli",
@@ -703,7 +705,7 @@ pub fn get_agent_config(agent_name: &str) -> Result<AcpAgentConfig> {
703705
let package_manager = detect_preferred_package_manager();
704706

705707
let (command, args) = match agent {
706-
// Claude and Codex use Zed's ACP adapters
708+
// Claude and Codex use external ACP adapters
707709
AgentKind::ClaudeCode | AgentKind::Codex => (
708710
package_manager.command().to_string(),
709711
vec![agent.acp_package().to_string()],
@@ -718,12 +720,28 @@ pub fn get_agent_config(agent_name: &str) -> Result<AcpAgentConfig> {
718720
),
719721
};
720722

723+
// Workaround: the v0.30.0+ Claude ACP adapter resolves its native
724+
// binary via require.resolve() on platform-specific optional deps.
725+
// On glibc Linux, bunx installs both musl and glibc variants; the
726+
// adapter tries musl first, require.resolve succeeds (file exists),
727+
// but execution fails (no musl loader). Point CLAUDE_CODE_EXECUTABLE
728+
// at the system binary to bypass the broken resolution.
729+
let mut env = HashMap::new();
730+
if agent == AgentKind::ClaudeCode
731+
&& let Ok(path) = which::which("claude")
732+
{
733+
env.insert(
734+
"CLAUDE_CODE_EXECUTABLE".to_string(),
735+
path.to_string_lossy().to_string(),
736+
);
737+
}
738+
721739
return Ok(AcpAgentConfig {
722740
agent,
723741
provider_slug: agent.slug().to_string(),
724742
command,
725743
args,
726-
env: HashMap::new(),
744+
env,
727745
provider_info: AcpProviderInfo {
728746
name: format!("{} ACP", agent.display_name()),
729747
..Default::default()
@@ -999,11 +1017,10 @@ mod tests {
9991017
"Command should be npx or bunx, got: {}",
10001018
config.command
10011019
);
1002-
// Uses Zed's ACP adapter
10031020
assert!(
10041021
config
10051022
.args
1006-
.contains(&"@zed-industries/claude-agent-acp".to_string())
1023+
.contains(&"@agentclientprotocol/claude-agent-acp@latest".to_string())
10071024
);
10081025
assert_eq!(config.provider_info.name, "Claude Code ACP");
10091026
}

0 commit comments

Comments
 (0)