fix(daemon): launch LSP servers with caller env

This commit is contained in:
2026-05-02 15:28:25 -04:00
parent 306771f92a
commit 04fd520438
5 changed files with 80 additions and 20 deletions

View File

@@ -10,6 +10,28 @@ import * as os from "node:os";
import * as path from "node:path";
import { spawn } from "node:child_process";
// Launch Context - Captures the caller/session environment used when the
// daemon spawns a new language server. Running servers keep their original
// process env; later requests for the same root reuse the existing server.
export interface LaunchContext {
env: Record<string, string>;
}
// Build Launch Context - Convert Node's optional-valued process.env into the
// concrete string map accepted by child_process.spawn(). Env contents are
// sensitive: keep them internal to requests and never log or expose them.
export function buildLaunchContext(
env: NodeJS.ProcessEnv = process.env,
): LaunchContext {
return {
env: Object.fromEntries(
Object.entries(env).filter((entry): entry is [string, string] => {
return typeof entry[1] === "string";
}),
),
};
}
// Request Shapes - Sent client -> daemon.
export type DaemonRequest =
| {
@@ -18,8 +40,15 @@ export type DaemonRequest =
file: string;
method: string;
params: Record<string, unknown>;
launch: LaunchContext;
}
| {
id: number;
op: "diagnostics";
file: string;
timeoutMs?: number;
launch: LaunchContext;
}
| { id: number; op: "diagnostics"; file: string; timeoutMs?: number }
| { id: number; op: "status" }
| { id: number; op: "shutdown" }
| { id: number; op: "destroy_server"; serverId?: string };
@@ -30,8 +59,14 @@ export type DaemonRequestWithoutId =
file: string;
method: string;
params: Record<string, unknown>;
launch: LaunchContext;
}
| {
op: "diagnostics";
file: string;
timeoutMs?: number;
launch: LaunchContext;
}
| { op: "diagnostics"; file: string; timeoutMs?: number }
| { op: "status" }
| { op: "shutdown" }
| { op: "destroy_server"; serverId?: string };