@@ -120,6 +120,121 @@ function sanitizeEnv(base: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
120120 return env ;
121121}
122122
123+ function pathEnvKey ( env : NodeJS . ProcessEnv ) : string {
124+ if ( process . platform !== "win32" ) return "PATH" ;
125+ if ( env . PATH !== undefined ) return "PATH" ;
126+ if ( env . Path !== undefined ) return "Path" ;
127+ return "PATH" ;
128+ }
129+
130+ function prependPathDir ( env : NodeJS . ProcessEnv , dir : string | null | undefined ) : void {
131+ if ( ! dir ?. trim ( ) ) return ;
132+ try {
133+ if ( ! fs . statSync ( dir ) . isDirectory ( ) ) return ;
134+ } catch {
135+ return ;
136+ }
137+ const key = pathEnvKey ( env ) ;
138+ const current = env [ key ] ?. trim ( ) ;
139+ const parts = current ? current . split ( path . delimiter ) : [ ] ;
140+ if ( parts . some ( ( part ) => path . resolve ( part ) === path . resolve ( dir ) ) ) return ;
141+ env [ key ] = current ? `${ dir } ${ path . delimiter } ${ current } ` : dir ;
142+ }
143+
144+ function prependPathList ( existing : string | undefined , root : string | null ) : string | undefined {
145+ if ( ! root ) return existing ;
146+ try {
147+ if ( ! fs . statSync ( root ) . isDirectory ( ) ) return existing ;
148+ } catch {
149+ return existing ;
150+ }
151+ const parts = ( existing ?? "" ) . split ( path . delimiter ) . filter ( Boolean ) ;
152+ if ( parts . some ( ( part ) => path . resolve ( part ) === path . resolve ( root ) ) ) return existing ;
153+ return [ root , ...parts ] . join ( path . delimiter ) ;
154+ }
155+
156+ function existingFilePath ( candidate : string | null | undefined ) : string | null {
157+ const trimmed = candidate ?. trim ( ) ;
158+ if ( ! trimmed ) return null ;
159+ try {
160+ const resolved = path . resolve ( trimmed ) ;
161+ return fs . statSync ( resolved ) . isFile ( ) ? resolved : null ;
162+ } catch {
163+ return null ;
164+ }
165+ }
166+
167+ function existingDirPath ( candidate : string | null | undefined ) : string | null {
168+ const trimmed = candidate ?. trim ( ) ;
169+ if ( ! trimmed ) return null ;
170+ try {
171+ const resolved = path . resolve ( trimmed ) ;
172+ return fs . statSync ( resolved ) . isDirectory ( ) ? resolved : null ;
173+ } catch {
174+ return null ;
175+ }
176+ }
177+
178+ function commandFileName ( name : string ) : string {
179+ return process . platform === "win32" ? `${ name } .cmd` : name ;
180+ }
181+
182+ function adeCommandNameCandidates ( env : NodeJS . ProcessEnv ) : string [ ] {
183+ const names = [
184+ env . ADE_CLI_PATH ? path . basename ( env . ADE_CLI_PATH , process . platform === "win32" ? ".cmd" : "" ) : "" ,
185+ env . ADE_CLI_INSTALL_NAME ,
186+ env . ADE_PACKAGE_CHANNEL === "alpha" || env . ADE_PACKAGE_CHANNEL === "beta"
187+ ? `ade-${ env . ADE_PACKAGE_CHANNEL } `
188+ : "" ,
189+ "ade" ,
190+ "ade-dev" ,
191+ ] ;
192+ return Array . from ( new Set ( names . map ( ( name ) => name ?. trim ( ) ) . filter ( ( name ) : name is string => Boolean ( name ) ) ) ) ;
193+ }
194+
195+ function findAdeCommandInBinDir ( binDir : string | null , env : NodeJS . ProcessEnv ) : string | null {
196+ if ( ! binDir ) return null ;
197+ for ( const name of adeCommandNameCandidates ( env ) ) {
198+ const candidate = existingFilePath ( path . join ( binDir , commandFileName ( name ) ) ) ;
199+ if ( ! candidate ) continue ;
200+ return candidate ;
201+ }
202+ return null ;
203+ }
204+
205+ function inferAdeCliBinDirFromEntry ( cliEntry : string | null ) : string | null {
206+ if ( ! cliEntry ) return null ;
207+ return existingDirPath ( path . join ( path . dirname ( cliEntry ) , "bin" ) ) ;
208+ }
209+
210+ function inferAdeCliEntryFromBinDir ( binDir : string | null ) : string | null {
211+ if ( ! binDir ) return null ;
212+ return existingFilePath ( path . resolve ( binDir , ".." , "cli.cjs" ) ) ;
213+ }
214+
215+ function applyCurrentAdeCliEnv ( env : NodeJS . ProcessEnv ) : void {
216+ const envCliEntry = existingFilePath ( env . ADE_CLI_ENTRY_PATH ) ;
217+ const argvCliEntry = existingFilePath ( typeof process . argv [ 1 ] === "string" ? process . argv [ 1 ] : null ) ;
218+ const binDir = existingDirPath ( env . ADE_CLI_BIN_DIR )
219+ ?? inferAdeCliBinDirFromEntry ( envCliEntry )
220+ ?? inferAdeCliBinDirFromEntry ( argvCliEntry ) ;
221+ if ( binDir ) {
222+ env . ADE_CLI_BIN_DIR = binDir ;
223+ prependPathDir ( env , binDir ) ;
224+ const commandPath = findAdeCommandInBinDir ( binDir , env ) ;
225+ if ( commandPath ) env . ADE_CLI_PATH = commandPath ;
226+ }
227+ const cliEntry = inferAdeCliEntryFromBinDir ( binDir ) ?? envCliEntry ?? argvCliEntry ;
228+ if ( cliEntry ) env . ADE_CLI_ENTRY_PATH = cliEntry ;
229+ else delete env . ADE_CLI_ENTRY_PATH ;
230+ const bundledSkillsRoot = binDir
231+ ? path . resolve ( binDir , ".." , ".." , "agent-skills" )
232+ : cliEntry
233+ ? path . resolve ( path . dirname ( cliEntry ) , ".." , "agent-skills" )
234+ : null ;
235+ env . ADE_AGENT_SKILLS_DIRS = prependPathList ( env . ADE_AGENT_SKILLS_DIRS , bundledSkillsRoot ) ;
236+ }
237+
123238function ensurePrivateDirectory ( dir : string ) : void {
124239 fs . mkdirSync ( dir , { recursive : true , mode : 0o700 } ) ;
125240 let fd : number | null = null ;
@@ -183,21 +298,25 @@ export function buildCursorSdkWorkerEnv(args: {
183298 workspacePath : string ;
184299 sessionId : string ;
185300} ) : NodeJS . ProcessEnv {
186- return {
301+ const env : NodeJS . ProcessEnv = {
187302 ...sanitizeEnv ( args . baseEnv ?? process . env ) ,
188303 HOME : args . userHomeDir ,
189304 USERPROFILE : args . userHomeDir ,
305+ ADE_DISABLE_RUNTIME_SERVICE_INSTALL : "1" ,
190306 ADE_CURSOR_SDK_SOCKET : args . socketPath ,
191307 ADE_CURSOR_SDK_LANE_ROOT : args . workspacePath ,
192308 ADE_CURSOR_SDK_SESSION_ID : args . sessionId ,
193309 ADE_CURSOR_SDK_STATE_ROOT : args . stateRoot ,
194310 } ;
311+ applyCurrentAdeCliEnv ( env ) ;
312+ return env ;
195313}
196314
197315export async function acquireCursorSdkConnection ( args : {
198316 poolKey : string ;
199317 projectRoot : string ;
200318 workspacePath : string ;
319+ baseEnv ?: NodeJS . ProcessEnv ;
201320 modelSdkId : string ;
202321 modelParams ?: CursorSdkModelParameterValue [ ] ;
203322 apiKey ?: string | null ;
@@ -258,6 +377,7 @@ async function createCursorSdkConnection(args: Parameters<typeof acquireCursorSd
258377 const child = fork ( workerPath , [ ] , {
259378 cwd : args . workspacePath ,
260379 env : buildCursorSdkWorkerEnv ( {
380+ baseEnv : args . baseEnv ,
261381 userHomeDir : paths . userHomeDir ,
262382 stateRoot : paths . stateRoot ,
263383 socketPath : paths . socketPath ,
0 commit comments