diff --git a/packages/pi-coding-agent/src/core/lsp/client.ts b/packages/pi-coding-agent/src/core/lsp/client.ts index 122a89731..6f04593d5 100644 --- a/packages/pi-coding-agent/src/core/lsp/client.ts +++ b/packages/pi-coding-agent/src/core/lsp/client.ts @@ -164,7 +164,7 @@ const CLIENT_CAPABILITIES = { function parseMessage( buffer: Buffer, -): { message: LspJsonRpcResponse | LspJsonRpcNotification; remaining: Buffer } | null { +): { message: LspJsonRpcResponse | LspJsonRpcNotification | null; remaining: Buffer } | null { const headerEndIndex = findHeaderEnd(buffer); if (headerEndIndex === -1) return null; @@ -182,10 +182,15 @@ function parseMessage( const messageText = new TextDecoder().decode(messageBytes); const remaining = Buffer.from(buffer.subarray(messageEnd)); - return { - message: JSON.parse(messageText), - remaining, - }; + let message: LspJsonRpcResponse | LspJsonRpcNotification; + try { + message = JSON.parse(messageText); + } catch { + // Malformed JSON from LSP server — skip this message and advance past it + return { message: null, remaining }; + } + + return { message, remaining }; } function findHeaderEnd(buffer: Uint8Array): number { @@ -239,6 +244,11 @@ async function startMessageReader(client: LspClient): Promise { const { message, remaining } = parsed; workingBuffer = remaining; + if (!message) { + parsed = parseMessage(workingBuffer); + continue; + } + if ("id" in message && message.id !== undefined) { const pending = client.pendingRequests.get(message.id); if (pending) { diff --git a/packages/pi-coding-agent/src/core/lsp/config.ts b/packages/pi-coding-agent/src/core/lsp/config.ts index 82283d741..fe6226dc1 100644 --- a/packages/pi-coding-agent/src/core/lsp/config.ts +++ b/packages/pi-coding-agent/src/core/lsp/config.ts @@ -2,7 +2,7 @@ import * as fs from "node:fs"; import { createRequire } from "node:module"; import * as os from "node:os"; import * as path from "node:path"; -import { execSync } from "node:child_process"; +import { spawnSync } from "node:child_process"; import YAML from "yaml"; import { globSync } from "glob"; import { CONFIG_DIR_NAME } from "../../config.js"; @@ -177,11 +177,9 @@ const LOCAL_BIN_PATHS: Array<{ markers: string[]; binDir: string }> = [ ]; function which(command: string): string | null { - try { - return execSync(`which ${command}`, { encoding: "utf-8" }).trim() || null; - } catch { - return null; - } + const result = spawnSync("which", [command], { encoding: "utf-8" }); + if (result.status !== 0) return null; + return result.stdout.trim() || null; } export function resolveCommand(command: string, cwd: string): string | null {