@@ -14,7 +14,11 @@ import {
1414 checkCommandAvailable ,
1515} from "../provider-runtime/command-check.js" ;
1616import { type CommandRunner , runCommandAsString } from "../provider-runtime/command-runner.js" ;
17- import { getLspToolDefinition } from "./definitions.js" ;
17+ import {
18+ getLspToolDefinition ,
19+ getManagedPrerequisites ,
20+ resolveManagedPythonCommand ,
21+ } from "./definitions.js" ;
1822import { FileManifestStore } from "./manifest-store.js" ;
1923
2024const EXCERPT_LIMIT = 400 ;
@@ -35,6 +39,7 @@ const RUST_ANALYZER_RELEASE_TAG = "2026-05-18";
3539export interface LspToolInstallManagerDeps extends CommandCheckDeps {
3640 manifestStore : FileManifestStore ;
3741 commandExists ?: CommandAvailabilityCheck ;
42+ platform ?: NodeJS . Platform ;
3843 runCommand ?: CommandRunner ;
3944}
4045
@@ -76,6 +81,7 @@ export class LspToolInstallManager {
7681 const definition = getLspToolDefinition ( input . serverKind ) ;
7782 const managed = definition . managed ;
7883 const jobId = randomUUID ( ) ;
84+ const platform = this . deps . platform ?? process . platform ;
7985
8086 if ( ! managed || input . workspace . targetRuntime !== "native" ) {
8187 return {
@@ -107,9 +113,17 @@ export class LspToolInstallManager {
107113 const commandExists =
108114 this . deps . commandExists ?? ( ( command : string ) => checkCommandAvailable ( command , this . deps ) ) ;
109115 const missingPrerequisites : string [ ] = [ ] ;
110- for ( const prerequisite of managed . prerequisites ) {
111- if ( ! ( await commandExists ( prerequisite ) ) ) {
112- missingPrerequisites . push ( prerequisite ) ;
116+ let pythonCommand : string | null = null ;
117+ if ( input . serverKind === "python" ) {
118+ pythonCommand = await resolveManagedPythonCommand ( commandExists , platform ) ;
119+ if ( ! pythonCommand ) {
120+ missingPrerequisites . push ( ...getManagedPrerequisites ( "python" , platform ) ) ;
121+ }
122+ } else {
123+ for ( const prerequisite of getManagedPrerequisites ( input . serverKind , platform ) ) {
124+ if ( ! ( await commandExists ( prerequisite ) ) ) {
125+ missingPrerequisites . push ( prerequisite ) ;
126+ }
113127 }
114128 }
115129
@@ -146,21 +160,19 @@ export class LspToolInstallManager {
146160 ? join (
147161 installRoot ,
148162 "venv" ,
149- process . platform === "win32" ? "Scripts" : "bin" ,
150- process . platform === "win32" ? "pylsp.exe" : "pylsp"
163+ platform === "win32" ? "Scripts" : "bin" ,
164+ platform === "win32" ? "pylsp.exe" : "pylsp"
151165 )
152166 : input . serverKind === "go"
153- ? join ( installRoot , "bin" , process . platform === "win32" ? "gopls.exe" : "gopls" )
154- : join (
155- installRoot ,
156- "bin" ,
157- process . platform === "win32" ? "rust-analyzer.exe" : "rust-analyzer"
158- ) ;
167+ ? join ( installRoot , "bin" , platform === "win32" ? "gopls.exe" : "gopls" )
168+ : join ( installRoot , "bin" , platform === "win32" ? "rust-analyzer.exe" : "rust-analyzer" ) ;
159169
160170 const plannedSteps = this . planInstallSteps ( {
161171 serverKind : input . serverKind ,
162172 installRoot,
163173 executablePath,
174+ platform,
175+ pythonCommand,
164176 version : managed . version ,
165177 } ) ;
166178
@@ -183,6 +195,7 @@ export class LspToolInstallManager {
183195 if ( ! managed ) {
184196 return ;
185197 }
198+ const platform = this . deps . platform ?? process . platform ;
186199
187200 job . status = "running" ;
188201 this . jobs . set ( job . jobId , job ) ;
@@ -193,16 +206,17 @@ export class LspToolInstallManager {
193206 ? join (
194207 installRoot ,
195208 "venv" ,
196- process . platform === "win32" ? "Scripts" : "bin" ,
197- process . platform === "win32" ? "pylsp.exe" : "pylsp"
209+ platform === "win32" ? "Scripts" : "bin" ,
210+ platform === "win32" ? "pylsp.exe" : "pylsp"
198211 )
199212 : serverKind === "go"
200- ? join ( installRoot , "bin" , process . platform === "win32" ? "gopls.exe" : "gopls" )
201- : join (
202- installRoot ,
203- "bin" ,
204- process . platform === "win32" ? "rust-analyzer.exe" : "rust-analyzer"
205- ) ;
213+ ? join ( installRoot , "bin" , platform === "win32" ? "gopls.exe" : "gopls" )
214+ : join ( installRoot , "bin" , platform === "win32" ? "rust-analyzer.exe" : "rust-analyzer" ) ;
215+
216+ const commandExists =
217+ this . deps . commandExists ?? ( ( command : string ) => checkCommandAvailable ( command , this . deps ) ) ;
218+ const pythonCommand =
219+ serverKind === "python" ? await resolveManagedPythonCommand ( commandExists , platform ) : null ;
206220
207221 mkdirSync ( dirname ( executablePath ) , { recursive : true } ) ;
208222
@@ -217,6 +231,8 @@ export class LspToolInstallManager {
217231 serverKind,
218232 installRoot,
219233 executablePath,
234+ platform,
235+ pythonCommand,
220236 version : managed . version ,
221237 } ) . find ( ( candidate ) => candidate . id === step . id ) ;
222238
@@ -225,9 +241,6 @@ export class LspToolInstallManager {
225241 }
226242
227243 if ( step . kind === "verify" ) {
228- const commandExists =
229- this . deps . commandExists ??
230- ( ( command : string ) => checkCommandAvailable ( command , this . deps ) ) ;
231244 const available = await commandExists ( executablePath ) ;
232245 if ( ! available ) {
233246 throw Object . assign ( new Error ( `Verification failed for ${ definition . displayName } ` ) , {
@@ -269,7 +282,7 @@ export class LspToolInstallManager {
269282 executablePath,
270283 installedAt : Date . now ( ) ,
271284 source : "managed" ,
272- platform : process . platform ,
285+ platform,
273286 } ) ;
274287
275288 job . status = "succeeded" ;
@@ -282,18 +295,20 @@ export class LspToolInstallManager {
282295 serverKind : LspServerKind ;
283296 installRoot : string ;
284297 executablePath : string ;
298+ platform : NodeJS . Platform ;
299+ pythonCommand : string | null ;
285300 version : string ;
286301 } ) : InstallPlanStep [ ] {
287302 if ( input . serverKind === "python" ) {
288303 const venvRoot = join ( input . installRoot , "venv" ) ;
289- const binDir = join ( venvRoot , process . platform === "win32" ? "Scripts" : "bin" ) ;
290- const pipPath = join ( binDir , process . platform === "win32" ? "pip.exe" : "pip" ) ;
304+ const binDir = join ( venvRoot , input . platform === "win32" ? "Scripts" : "bin" ) ;
305+ const pipPath = join ( binDir , input . platform === "win32" ? "pip.exe" : "pip" ) ;
291306 return [
292307 {
293308 id : "create-python-venv" ,
294309 title : "Create Python virtual environment" ,
295310 kind : "install" ,
296- command : "python3" ,
311+ command : input . pythonCommand ?? "python3" ,
297312 args : [ "-m" , "venv" , venvRoot ] ,
298313 cwd : input . installRoot ,
299314 } ,
0 commit comments