1
+ import { homedir } from 'os' ;
1
2
import { arch } from 'process' ;
2
3
import type { ConfigurationChangeEvent } from 'vscode' ;
3
4
import { Disposable , env , ProgressLocation , Uri , window , workspace } from 'vscode' ;
4
5
import type { Container } from '../../../../container' ;
6
+ import type { SubscriptionChangeEvent } from '../../../../plus/gk/subscriptionService' ;
5
7
import { registerCommand } from '../../../../system/-webview/command' ;
6
8
import { configuration } from '../../../../system/-webview/configuration' ;
7
9
import { getContext } from '../../../../system/-webview/context' ;
@@ -26,6 +28,7 @@ export class GkCliIntegrationProvider implements Disposable {
26
28
constructor ( private readonly container : Container ) {
27
29
this . _disposable = Disposable . from (
28
30
configuration . onDidChange ( e => this . onConfigurationChanged ( e ) ) ,
31
+ this . container . subscription . onDidChange ( this . onSubscriptionChanged , this ) ,
29
32
...this . registerCommands ( ) ,
30
33
) ;
31
34
@@ -260,7 +263,7 @@ export class GkCliIntegrationProvider implements Disposable {
260
263
261
264
// Configure the MCP server in settings.json
262
265
try {
263
- const installOutput = await run ( mcpFileName , [ 'install' ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
266
+ const installOutput = await run ( platform === 'windows' ? mcpFileName : `./ ${ mcpFileName } ` , [ 'install' ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
264
267
const directory = installOutput . match ( / D i r e c t o r y : ( .* ) / ) ;
265
268
if ( directory != null ) {
266
269
try {
@@ -276,60 +279,57 @@ export class GkCliIntegrationProvider implements Disposable {
276
279
'utf8' ,
277
280
) ;
278
281
} else {
279
- await run (
280
- 'export' ,
281
- [ `PATH=$PATH:${ directoryPath } ` ] ,
282
- 'utf8' ,
283
- ) ;
282
+ // For Unix-like systems, detect and modify the appropriate shell profile
283
+ const homeDir = homedir ( ) ;
284
+ // Try to detect which shell profile exists and is in use
285
+ const possibleProfiles = [
286
+ { path : `${ homeDir } /.zshrc` , shell : 'zsh' } ,
287
+ { path : `${ homeDir } /.zprofile` , shell : 'zsh' } ,
288
+ { path : `${ homeDir } /.bashrc` , shell : 'bash' } ,
289
+ { path : `${ homeDir } /.profile` , shell : 'sh' }
290
+ ] ;
291
+
292
+ // Find the first profile that exists
293
+ let shellProfile ;
294
+ for ( const profile of possibleProfiles ) {
295
+ try {
296
+ await workspace . fs . stat ( Uri . file ( profile . path ) ) ;
297
+ shellProfile = profile . path ;
298
+ break ;
299
+ } catch {
300
+ // Profile doesn't exist, try next one
301
+ }
302
+ }
303
+
304
+ if ( shellProfile != null ) {
305
+ await run (
306
+ 'sh' ,
307
+ [ '-c' , `echo '# Added by GitLens for MCP support' >> ${ shellProfile } && echo 'export PATH="$PATH:${ directoryPath } "' >> ${ shellProfile } ` ] ,
308
+ 'utf8' ,
309
+ ) ;
310
+ } else {
311
+ Logger . warn ( 'MCP Install: Failed to find shell profile to update PATH' ) ;
312
+ }
284
313
}
285
314
} catch ( error ) {
286
- Logger . warn ( `Failed to add GK directory to PATH: ${ error } ` ) ;
315
+ Logger . warn ( `MCP Install: Failed to add directory to PATH: ${ error } ` ) ;
287
316
}
288
317
} else {
289
- Logger . warn ( 'Failed to find directory in GK install output' ) ;
318
+ Logger . warn ( 'MCP Install: Failed to find directory in install output' ) ;
290
319
}
291
320
292
- await run ( mcpFileName , [ 'mcp' , 'install' , appName , ...isInsiders ? [ '--file-path' , settingsPath ] : [ ] ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
293
-
321
+ await run ( platform === 'windows' ? mcpFileName : `./${ mcpFileName } ` , [ 'mcp' , 'install' , appName , ...isInsiders ? [ '--file-path' , settingsPath ] : [ ] ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
294
322
const gkAuth = ( await this . container . subscription . getAuthenticationSession ( ) ) ?. accessToken ;
295
323
if ( gkAuth != null ) {
296
- await run ( mcpFileName , [ 'auth' , 'login' , '-t' , gkAuth ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
297
- }
298
- } catch {
299
- // Try alternative execution methods based on platform
300
- try {
301
- Logger . log ( 'Attempting alternative execution method for MCP install...' ) ;
302
- if ( platform === 'windows' ) {
303
- // On Windows, try running with cmd.exe
304
- await run (
305
- 'cmd.exe' ,
306
- [
307
- '/c' ,
308
- `"${ mcpExtractedPath . fsPath } "` ,
309
- 'mcp' ,
310
- 'install' ,
311
- appName ,
312
- ...isInsiders ? [ '--file-path' , settingsPath ] : [ ] ,
313
- ] ,
314
- 'utf8' ,
315
- ) ;
316
- } else {
317
- // On Unix-like systems, try running with sh
318
- await run (
319
- '/bin/sh' ,
320
- // ['-c', `"${mcpExtractedPath.fsPath}" mcp install vscode --file-path "${settingsPath}"`],
321
- [ '-c' , `"${ mcpExtractedPath . fsPath } " mcp install ${ appName } ${ isInsiders ? `--file-path ${ settingsPath } ` : '' } ` ] ,
322
- 'utf8' ,
323
- ) ;
324
- }
325
- } catch ( altError ) {
326
- const errorMsg = `MCP server configuration failed: ${ altError } ` ;
327
- Logger . error ( errorMsg ) ;
328
- throw new Error ( errorMsg ) ;
324
+ await run ( platform === 'windows' ? mcpFileName : `./${ mcpFileName } ` , [ 'auth' , 'login' , '-t' , gkAuth ] , 'utf8' , { cwd : mcpExtractedFolderPath . fsPath } ) ;
329
325
}
330
- }
331
326
332
- Logger . log ( 'MCP configuration completed' ) ;
327
+ Logger . log ( 'MCP configuration completed' ) ;
328
+ } catch ( error ) {
329
+ const errorMsg = `MCP server configuration failed: ${ error } ` ;
330
+ Logger . error ( errorMsg ) ;
331
+ throw new Error ( errorMsg ) ;
332
+ }
333
333
} finally {
334
334
// Always clean up downloaded/extracted files, even if something failed
335
335
if ( mcpInstallerPath != null ) {
@@ -388,6 +388,21 @@ export class GkCliIntegrationProvider implements Disposable {
388
388
}
389
389
}
390
390
391
+ private async onSubscriptionChanged ( e : SubscriptionChangeEvent ) : Promise < void > {
392
+ const mcpInstallStatus = this . container . storage . get ( 'ai:mcp:attemptInstall' ) ;
393
+ const mcpDirectoryPath = this . container . storage . get ( 'gk:cli:installedPath' ) ;
394
+ const platform = getPlatform ( ) ;
395
+ if ( e . current ?. account ?. id != null && e . current . account . id !== e . previous ?. account ?. id && mcpInstallStatus === 'completed' && mcpDirectoryPath != null ) {
396
+ const currentSessionToken = ( await this . container . subscription . getAuthenticationSession ( ) ) ?. accessToken ;
397
+ if ( currentSessionToken != null ) {
398
+ try {
399
+ await run ( platform === 'windows' ? 'gk.exe' : './gk' , [ 'auth' , 'login' , '-t' , currentSessionToken ] , 'utf8' , { cwd : mcpDirectoryPath } ) ;
400
+ } catch { }
401
+ }
402
+ }
403
+ }
404
+
405
+
391
406
private registerCommands ( ) : Disposable [ ] {
392
407
return [ registerCommand ( 'gitlens.ai.mcp.install' , ( ) => this . installMCPIfNeeded ( ) ) ] ;
393
408
}
0 commit comments