From 1a9d3cebcdf98bc650af99902d26c49de30904b6 Mon Sep 17 00:00:00 2001 From: Steffen Deusch Date: Mon, 27 Apr 2026 11:54:12 +0200 Subject: [PATCH] detect glibc and use correct binary (#598) On Linux, the current code prefers the musl binary if multiple versions are installed, but it actually crashes on glibc systems. Supersedes https://github.com/agentclientprotocol/claude-agent-acp/pull/597. Importantly, we need to pass the detected binary to `pathToClaudeCodeExecutable`, otherwise the SDK itself selects the wrong version. See https://github.com/tidewave-ai/tidewave_app/issues/141. Closes https://github.com/tidewave-ai/tidewave_app/issues/141. --- src/acp-agent.ts | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/acp-agent.ts b/src/acp-agent.ts index 01d5d92b..0d2e83bd 100644 --- a/src/acp-agent.ts +++ b/src/acp-agent.ts @@ -274,12 +274,22 @@ export async function claudeCliPath(): Promise { const { createRequire } = await import("node:module"); const req = createRequire(import.meta.resolve("@anthropic-ai/claude-agent-sdk")); const ext = process.platform === "win32" ? ".exe" : ""; + // On linux, both glibc and musl variants may be installed side-by-side + // (e.g. bunx hydrates every optional dep), so picking one by trial is + // unreliable: the wrong binary segfaults at runtime instead of failing to + // spawn. Detect the runtime libc and prefer the matching variant, falling + // back to the other only if the preferred one isn't installed. const candidates = process.platform === "linux" - ? [ - `@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl/claude${ext}`, - `@anthropic-ai/claude-agent-sdk-linux-${process.arch}/claude${ext}`, - ] + ? isMuslLibc() + ? [ + `@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl/claude${ext}`, + `@anthropic-ai/claude-agent-sdk-linux-${process.arch}/claude${ext}`, + ] + : [ + `@anthropic-ai/claude-agent-sdk-linux-${process.arch}/claude${ext}`, + `@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl/claude${ext}`, + ] : [`@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}/claude${ext}`]; for (const candidate of candidates) { try { @@ -294,6 +304,15 @@ export async function claudeCliPath(): Promise { ); } +function isMuslLibc(): boolean { + // process.report.getReport().header.glibcVersionRuntime is populated when + // Node is dynamically linked against glibc, and absent on musl. + const report = process.report?.getReport() as + | { header?: { glibcVersionRuntime?: string } } + | undefined; + return !report?.header?.glibcVersionRuntime; +} + function shouldHideClaudeAuth(): boolean { return process.argv.includes("--hide-claude-auth"); } @@ -1760,7 +1779,7 @@ export class ClaudeAcpAgent implements Agent { allowDangerouslySkipPermissions: ALLOW_BYPASS, permissionMode, canUseTool: this.canUseTool(sessionId), - pathToClaudeCodeExecutable: process.env.CLAUDE_CODE_EXECUTABLE, + pathToClaudeCodeExecutable: process.env.CLAUDE_CODE_EXECUTABLE ?? (await claudeCliPath()), extraArgs: { ...userProvidedOptions?.extraArgs, "replay-user-messages": "",