11// Copyright (c) Microsoft Corporation.
22// Licensed under the MIT License.
33
4- import { inject , injectable , optional } from 'inversify' ;
4+ import { inject , injectable , optional , named } from 'inversify' ;
55import {
66 CancellationToken ,
77 NotebookDocument ,
@@ -13,7 +13,8 @@ import {
1313 NotebookController ,
1414 CancellationTokenSource ,
1515 Disposable ,
16- l10n
16+ l10n ,
17+ env
1718} from 'vscode' ;
1819import { IExtensionSyncActivationService } from '../../platform/activation/types' ;
1920import { IDisposableRegistry } from '../../platform/common/types' ;
@@ -42,6 +43,9 @@ import { IDeepnoteNotebookManager } from '../types';
4243import { IDeepnoteRequirementsHelper } from './deepnoteRequirementsHelper.node' ;
4344import { DeepnoteProject } from './deepnoteTypes' ;
4445import { IKernelProvider , IKernel } from '../../kernels/types' ;
46+ import { DeepnoteKernelError } from '../../platform/errors/deepnoteKernelErrors' ;
47+ import { STANDARD_OUTPUT_CHANNEL } from '../../platform/common/constants' ;
48+ import { IOutputChannel } from '../../platform/common/types' ;
4549
4650/**
4751 * Automatically selects and starts Deepnote kernel for .deepnote notebooks
@@ -78,7 +82,8 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
7882 @inject ( IDeepnoteInitNotebookRunner ) private readonly initNotebookRunner : IDeepnoteInitNotebookRunner ,
7983 @inject ( IDeepnoteNotebookManager ) private readonly notebookManager : IDeepnoteNotebookManager ,
8084 @inject ( IKernelProvider ) private readonly kernelProvider : IKernelProvider ,
81- @inject ( IDeepnoteRequirementsHelper ) private readonly requirementsHelper : IDeepnoteRequirementsHelper
85+ @inject ( IDeepnoteRequirementsHelper ) private readonly requirementsHelper : IDeepnoteRequirementsHelper ,
86+ @inject ( IOutputChannel ) @named ( STANDARD_OUTPUT_CHANNEL ) private readonly outputChannel : IOutputChannel
8287 ) { }
8388
8489 public activate ( ) {
@@ -129,9 +134,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
129134 // Don't await - let it happen in background so notebook opens quickly
130135 void this . ensureKernelSelected ( notebook ) . catch ( ( error ) => {
131136 logger . error ( `Failed to auto-select Deepnote kernel for ${ getDisplayPath ( notebook . uri ) } ` , error ) ;
132- void window . showErrorMessage (
133- l10n . t ( 'Failed to load Deepnote kernel. Please check the output for details.' )
134- ) ;
137+ void this . handleKernelSelectionError ( error ) ;
135138 } ) ;
136139 }
137140
@@ -342,16 +345,13 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
342345 logger . info ( `Using base interpreter: ${ getDisplayPath ( interpreter . uri ) } ` ) ;
343346
344347 // Ensure deepnote-toolkit is installed in a venv and get the venv interpreter
348+ // Will throw typed errors on failure (DeepnoteVenvCreationError or DeepnoteToolkitInstallError)
345349 progress . report ( { message : l10n . t ( 'Installing Deepnote toolkit...' ) } ) ;
346350 const venvInterpreter = await this . toolkitInstaller . ensureInstalled (
347351 interpreter ,
348352 baseFileUri ,
349353 progressToken
350354 ) ;
351- if ( ! venvInterpreter ) {
352- logger . error ( 'Failed to set up Deepnote toolkit environment' ) ;
353- return ; // Exit gracefully
354- }
355355
356356 logger . info ( `Deepnote toolkit venv ready at: ${ getDisplayPath ( venvInterpreter . uri ) } ` ) ;
357357
@@ -553,4 +553,61 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
553553 this . loadingControllers . set ( notebookKey , loadingController ) ;
554554 logger . info ( `Created loading controller for ${ notebookKey } ` ) ;
555555 }
556+
557+ /**
558+ * Handle kernel selection errors with user-friendly messages and actions
559+ */
560+ private async handleKernelSelectionError ( error : unknown ) : Promise < void > {
561+ // Handle DeepnoteKernelError types with specific guidance
562+ if ( error instanceof DeepnoteKernelError ) {
563+ // Log the technical details
564+ logger . error ( error . getErrorReport ( ) ) ;
565+
566+ // Show user-friendly error with actions
567+ const showOutputAction = l10n . t ( 'Show Output' ) ;
568+ const copyErrorAction = l10n . t ( 'Copy Error Details' ) ;
569+ const actions : string [ ] = [ showOutputAction , copyErrorAction ] ;
570+
571+ const troubleshootingHeader = l10n . t ( 'Troubleshooting:' ) ;
572+ const troubleshootingSteps = error . troubleshootingSteps
573+ . slice ( 0 , 3 )
574+ . map ( ( step , i ) => `${ i + 1 } . ${ step } ` )
575+ . join ( '\n' ) ;
576+
577+ const selectedAction = await window . showErrorMessage (
578+ `${ error . userMessage } \n\n${ troubleshootingHeader } \n${ troubleshootingSteps } ` ,
579+ { modal : false } ,
580+ ...actions
581+ ) ;
582+
583+ if ( selectedAction === showOutputAction ) {
584+ this . outputChannel . show ( ) ;
585+ } else if ( selectedAction === copyErrorAction ) {
586+ try {
587+ await env . clipboard . writeText ( error . getErrorReport ( ) ) ;
588+ void window . showInformationMessage ( l10n . t ( 'Error details copied to clipboard' ) ) ;
589+ } catch ( clipboardError ) {
590+ logger . error ( 'Failed to copy error details to clipboard' , clipboardError ) ;
591+ void window . showErrorMessage ( l10n . t ( 'Failed to copy error details to clipboard' ) ) ;
592+ }
593+ }
594+
595+ return ;
596+ }
597+
598+ // Handle generic errors
599+ const errorMessage = error instanceof Error ? error . message : String ( error ) ;
600+ logger . error ( `Deepnote kernel error: ${ errorMessage } ` ) ;
601+
602+ const showOutputAction = l10n . t ( 'Show Output' ) ;
603+ const selectedAction = await window . showErrorMessage (
604+ l10n . t ( 'Failed to load Deepnote kernel: {0}' , errorMessage ) ,
605+ { modal : false } ,
606+ showOutputAction
607+ ) ;
608+
609+ if ( selectedAction === showOutputAction ) {
610+ this . outputChannel . show ( ) ;
611+ }
612+ }
556613}
0 commit comments