@@ -98,6 +98,18 @@ export class GkCliIntegrationProvider implements Disposable {
9898 if ( this . container . telemetry . enabled ) {
9999 this . container . telemetry . sendEvent ( 'mcp/setup/started' , { source : commandSource } ) ;
100100 }
101+
102+ if ( isWeb ) {
103+ void window . showErrorMessage ( 'GitKraken MCP installation is not supported on this platform.' ) ;
104+ if ( this . container . telemetry . enabled ) {
105+ this . container . telemetry . sendEvent ( 'mcp/setup/failed' , {
106+ reason : 'web environment unsupported' ,
107+ source : commandSource ,
108+ } ) ;
109+ }
110+ return ;
111+ }
112+
101113 const appName = toMcpInstallProvider ( await getHostAppName ( ) ) ;
102114 if ( appName == null ) {
103115 void window . showInformationMessage ( `Failed to install MCP integration: Could not determine app name` ) ;
@@ -125,80 +137,74 @@ export class GkCliIntegrationProvider implements Disposable {
125137 return ;
126138 }
127139
128- let cliInstall = this . container . storage . get ( 'gk:cli:install' ) ;
129- let cliPath = this . container . storage . get ( 'gk:cli:path' ) ;
130- let cliProxyFileExists = true ;
131- if ( cliPath != null ) {
132- try {
133- await workspace . fs . stat (
134- Uri . joinPath ( Uri . file ( cliPath ) , getPlatform ( ) === 'windows' ? 'gk.exe' : 'gk' ) ,
135- ) ;
136- } catch {
137- cliProxyFileExists = false ;
138- }
139- }
140- if ( cliInstall ?. status !== 'completed' || cliPath == null || ! cliProxyFileExists ) {
141- try {
142- await window . withProgress (
143- {
144- location : ProgressLocation . Notification ,
145- title : 'Setting up MCP integration...' ,
146- cancellable : false ,
147- } ,
148- async ( ) => {
149- cliVersion = await this . installCLI ( ) ;
150- } ,
151- ) ;
152- } catch ( ex ) {
153- let failureReason = 'unknown error' ;
154- if ( ex instanceof CLIInstallError ) {
155- switch ( ex . reason ) {
156- case CLIInstallErrorReason . WebEnvironmentUnsupported :
157- void window . showErrorMessage (
158- 'MCP installation is not supported in the web environment.' ,
159- ) ;
160- failureReason = 'web environment unsupported' ;
161- break ;
162- case CLIInstallErrorReason . UnsupportedPlatform :
163- void window . showErrorMessage ( 'MCP installation is not supported on this platform.' ) ;
164- failureReason = 'unsupported platform' ;
165- break ;
166- case CLIInstallErrorReason . ProxyUrlFetch :
167- case CLIInstallErrorReason . ProxyUrlFormat :
168- case CLIInstallErrorReason . ProxyFetch :
169- case CLIInstallErrorReason . ProxyDownload :
170- case CLIInstallErrorReason . ProxyExtract :
171- case CLIInstallErrorReason . CoreDirectory :
172- case CLIInstallErrorReason . CoreInstall :
173- void window . showErrorMessage ( 'Failed to install MCP server locally.' ) ;
174- failureReason = 'local installation failed' ;
175- break ;
176- default :
177- void window . showErrorMessage (
178- `Failed to install MCP integration: ${ ex instanceof Error ? ex . message : 'Unknown error during installation' } ` ,
179- ) ;
180- break ;
181- }
140+ let cliVersion : string | undefined ;
141+ let cliPath : string | undefined ;
142+ try {
143+ await window . withProgress (
144+ {
145+ location : ProgressLocation . Notification ,
146+ title : 'Setting up the GitKraken MCP...' ,
147+ cancellable : false ,
148+ } ,
149+ async ( ) => {
150+ const { cliVersion : installedVersion , cliPath : installedPath } = await this . installCLI (
151+ false ,
152+ source ,
153+ ) ;
154+ cliVersion = installedVersion ;
155+ cliPath = installedPath ;
156+ } ,
157+ ) ;
158+ } catch ( ex ) {
159+ let failureReason = 'unknown error' ;
160+ if ( ex instanceof CLIInstallError ) {
161+ switch ( ex . reason ) {
162+ case CLIInstallErrorReason . WebEnvironmentUnsupported :
163+ void window . showErrorMessage (
164+ 'GitKraken MCP installation is not supported on this platform.' ,
165+ ) ;
166+ failureReason = 'web environment unsupported' ;
167+ break ;
168+ case CLIInstallErrorReason . UnsupportedPlatform :
169+ void window . showErrorMessage (
170+ 'GitKraken MCP installation is not supported on this platform.' ,
171+ ) ;
172+ failureReason = 'unsupported platform' ;
173+ break ;
174+ case CLIInstallErrorReason . ProxyUrlFetch :
175+ case CLIInstallErrorReason . ProxyUrlFormat :
176+ case CLIInstallErrorReason . ProxyFetch :
177+ case CLIInstallErrorReason . ProxyDownload :
178+ case CLIInstallErrorReason . ProxyExtract :
179+ case CLIInstallErrorReason . CoreDirectory :
180+ case CLIInstallErrorReason . CoreInstall :
181+ void window . showErrorMessage ( 'Failed to install the GitKraken MCP server locally.' ) ;
182+ failureReason = 'local installation failed' ;
183+ break ;
184+ default :
185+ void window . showErrorMessage (
186+ `Failed to install the GitKraken MCP integration: ${ ex instanceof Error ? ex . message : 'Unknown error.' } ` ,
187+ ) ;
188+ break ;
182189 }
190+ }
183191
184- if ( this . container . telemetry . enabled ) {
185- this . container . telemetry . sendEvent ( 'mcp/setup/failed' , {
186- reason : failureReason ,
187- 'error.message' : ex instanceof Error ? ex . message : 'Unknown error during installation' ,
188- source : commandSource ,
189- } ) ;
190- }
192+ if ( this . container . telemetry . enabled ) {
193+ this . container . telemetry . sendEvent ( 'mcp/setup/failed' , {
194+ reason : failureReason ,
195+ 'error.message' : ex instanceof Error ? ex . message : 'Unknown error' ,
196+ source : commandSource ,
197+ } ) ;
191198 }
199+ return ;
192200 }
193201
194- cliInstall = this . container . storage . get ( 'gk:cli:install' ) ;
195- cliPath = this . container . storage . get ( 'gk:cli:path' ) ;
196- if ( cliInstall ?. status !== 'completed' || cliPath == null ) {
197- void window . showErrorMessage ( 'Failed to install MCP integration: Unknown error during installation.' ) ;
202+ if ( cliPath == null ) {
203+ void window . showErrorMessage ( 'Failed to install the GitKraken MCP: Unknown error.' ) ;
198204 if ( this . container . telemetry . enabled ) {
199205 this . container . telemetry . sendEvent ( 'mcp/setup/failed' , {
200206 reason : 'unknown error' ,
201- 'error.message' : 'Unknown error during installation ' ,
207+ 'error.message' : 'Unknown error' ,
202208 source : commandSource ,
203209 'cli.version' : cliVersion ,
204210 } ) ;
@@ -208,7 +214,7 @@ export class GkCliIntegrationProvider implements Disposable {
208214
209215 if ( appName !== 'cursor' && appName !== 'vscode' && appName !== 'vscode-insiders' ) {
210216 const confirmation = await window . showInformationMessage (
211- `MCP configured successfully. Click 'Finish' to add it to your MCP server list and complete the installation .` ,
217+ `GitKraken MCP installed successfully. Click 'Finish' to add it to your MCP server list and complete the setup .` ,
212218 { modal : true } ,
213219 { title : 'Finish' } ,
214220 { title : 'Cancel' , isCloseAffordance : true } ,
@@ -234,6 +240,13 @@ export class GkCliIntegrationProvider implements Disposable {
234240
235241 output = output . trim ( ) ;
236242 if ( output === 'GitKraken MCP Server Successfully Installed!' ) {
243+ if ( this . container . telemetry . enabled ) {
244+ this . container . telemetry . sendEvent ( 'mcp/setup/completed' , {
245+ requiresUserCompletion : false ,
246+ source : commandSource ,
247+ 'cli.version' : cliVersion ,
248+ } ) ;
249+ }
237250 return ;
238251 } else if ( output . includes ( 'not a supported MCP client' ) ) {
239252 if ( this . container . telemetry . enabled ) {
@@ -260,15 +273,14 @@ export class GkCliIntegrationProvider implements Disposable {
260273 } ) ;
261274 }
262275 Logger . error ( `Unexpected output from mcp install command: ${ output } ` , scope ) ;
263- void window . showErrorMessage ( `Failed to install MCP integration: error getting install URL ` ) ;
276+ void window . showErrorMessage ( `Failed to install the GitKrakenMCP integration: unknown error ` ) ;
264277 return ;
265278 }
266279
267280 await openUrl ( output ) ;
268281 if ( this . container . telemetry . enabled ) {
269282 this . container . telemetry . sendEvent ( 'mcp/setup/completed' , {
270- requiresUserCompletion :
271- appName === 'cursor' || appName === 'vscode' || appName === 'vscode-insiders' ,
283+ requiresUserCompletion : true ,
272284 source : commandSource ,
273285 'cli.version' : cliVersion ,
274286 } ) ;
@@ -278,24 +290,41 @@ export class GkCliIntegrationProvider implements Disposable {
278290 if ( this . container . telemetry . enabled ) {
279291 this . container . telemetry . sendEvent ( 'mcp/setup/failed' , {
280292 reason : 'unknown error' ,
281- 'error.message' : ex instanceof Error ? ex . message : 'Unknown error during installation ' ,
293+ 'error.message' : ex instanceof Error ? ex . message : 'Unknown error' ,
282294 source : commandSource ,
283295 'cli.version' : cliVersion ,
284296 } ) ;
285297 }
286298
287299 void window . showErrorMessage (
288- `Failed to install MCP integration: ${ ex instanceof Error ? ex . message : String ( ex ) } ` ,
300+ `Failed to install the GitKraken MCP integration: ${ ex instanceof Error ? ex . message : 'Unknown error' } ` ,
289301 ) ;
290302 }
291303 }
292304
293305 @gate ( )
294- private async installCLI ( autoInstall ?: boolean , source ?: Sources ) : Promise < string | undefined > {
306+ private async installCLI (
307+ autoInstall ?: boolean ,
308+ source ?: Sources ,
309+ ) : Promise < { cliVersion ?: string ; cliPath ?: string } > {
295310 let attempts = 0 ;
296311 let cliVersion : string | undefined ;
312+ let cliPath : string | undefined ;
313+ const cliInstall = this . container . storage . get ( 'gk:cli:install' ) ;
314+ if ( autoInstall ) {
315+ if ( cliInstall ?. status === 'completed' ) {
316+ cliVersion = cliInstall . version ;
317+ cliPath = this . container . storage . get ( 'gk:cli:path' ) ;
318+ return { cliVersion : cliVersion , cliPath : cliPath } ;
319+ } else if (
320+ cliInstall ?. status === 'unsupported' ||
321+ ( cliInstall ?. status === 'attempted' && cliInstall . attempts >= 5 )
322+ ) {
323+ return { cliVersion : undefined , cliPath : undefined } ;
324+ }
325+ }
326+
297327 try {
298- const cliInstall = this . container . storage . get ( 'gk:cli:install' ) ;
299328 attempts = cliInstall ?. attempts ?? 0 ;
300329 attempts += 1 ;
301330 if ( this . container . telemetry . enabled ) {
@@ -456,7 +485,7 @@ export class GkCliIntegrationProvider implements Disposable {
456485 // Use the run function to extract the installer file from the installer zip
457486 if ( platform === 'windows' ) {
458487 // On Windows, use PowerShell to extract the zip file.
459- // Force overwrite if the file already exists and the force param is true
488+ // Force overwrite if the file already exists with -Force
460489 await run (
461490 'powershell.exe' ,
462491 [
@@ -466,7 +495,7 @@ export class GkCliIntegrationProvider implements Disposable {
466495 'utf8' ,
467496 ) ;
468497 } else {
469- // On Unix-like systems, use the unzip command to extract the zip file
498+ // On Unix-like systems, use the unzip command to extract the zip file, forcing overwrite with -o
470499 await run ( 'unzip' , [ '-o' , cliProxyZipFilePath . fsPath , '-d' , globalStoragePath . fsPath ] , 'utf8' ) ;
471500 }
472501
@@ -475,8 +504,11 @@ export class GkCliIntegrationProvider implements Disposable {
475504 globalStoragePath ,
476505 platform === 'windows' ? 'gk.exe' : 'gk' ,
477506 ) ;
507+
508+ // This will throw if the file doesn't exist
478509 await workspace . fs . stat ( cliExtractedProxyFilePath ) ;
479510 void this . container . storage . store ( 'gk:cli:path' , globalStoragePath . fsPath ) . catch ( ) ;
511+ cliPath = globalStoragePath . fsPath ;
480512 } catch ( ex ) {
481513 throw new CLIInstallError (
482514 CLIInstallErrorReason . ProxyExtract ,
@@ -501,7 +533,7 @@ export class GkCliIntegrationProvider implements Disposable {
501533
502534 Logger . log ( 'CLI install completed.' ) ;
503535 void this . container . storage
504- . store ( 'gk:cli:install' , { status : 'completed' , attempts : attempts } )
536+ . store ( 'gk:cli:install' , { status : 'completed' , attempts : attempts , version : cliVersion } )
505537 . catch ( ) ;
506538 if ( this . container . telemetry . enabled ) {
507539 this . container . telemetry . sendEvent ( 'cli/install/succeeded' , {
@@ -553,7 +585,7 @@ export class GkCliIntegrationProvider implements Disposable {
553585 }
554586 }
555587
556- return cliVersion ;
588+ return { cliVersion : cliVersion , cliPath : cliPath } ;
557589 }
558590
559591 private async runCLICommand (
0 commit comments