11import { isAxiosError } from "axios"
22import { Api } from "coder/site/src/api/api"
3- import { Workspace } from "coder/site/src/api/typesGenerated"
3+ import { SSHConfigResponse , Workspace } from "coder/site/src/api/typesGenerated"
44import find from "find-process"
55import * as fs from "fs/promises"
66import * as jsonc from "jsonc-parser"
@@ -9,7 +9,14 @@ import * as path from "path"
99import prettyBytes from "pretty-bytes"
1010import * as semver from "semver"
1111import * as vscode from "vscode"
12- import { createHttpAgent , makeCoderSdk , needToken , startWorkspaceIfStoppedOrFailed , waitForBuild } from "./api"
12+ import {
13+ createHttpAgent ,
14+ fetchSSHConfig ,
15+ makeCoderSdk ,
16+ needToken ,
17+ startWorkspaceIfStoppedOrFailed ,
18+ waitForBuild ,
19+ } from "./api"
1320import { extractAgents } from "./api-helper"
1421import * as cli from "./cliManager"
1522import { Commands } from "./commands"
@@ -19,7 +26,7 @@ import { Inbox } from "./inbox"
1926import { SSHConfig , SSHValues , mergeSSHConfigValues } from "./sshConfig"
2027import { computeSSHProperties , sshSupportsSetEnv } from "./sshSupport"
2128import { Storage } from "./storage"
22- import { AuthorityPrefix , expandPath , parseRemoteAuthority } from "./util"
29+ import { AuthorityPrefix , expandPath , maybeCoderConnectAddr , parseRemoteAuthority } from "./util"
2330import { WorkspaceMonitor } from "./workspaceMonitor"
2431
2532export interface RemoteDetails extends vscode . Disposable {
@@ -469,9 +476,19 @@ export class Remote {
469476//
470477// If we didn't write to the SSH config file, connecting would fail with
471478// "Host not found".
479+ let sshConfigResponse :SSHConfigResponse
472480try {
473481this . storage . writeToCoderOutputChannel ( "Updating SSH config..." )
474- await this . updateSSHConfig ( workspaceRestClient , parts . label , parts . host , binaryPath , logDir , featureSet )
482+ sshConfigResponse = await fetchSSHConfig ( workspaceRestClient , this . vscodeProposed )
483+ await this . updateSSHConfig (
484+ workspaceRestClient ,
485+ parts . label ,
486+ parts . host ,
487+ binaryPath ,
488+ logDir ,
489+ featureSet ,
490+ sshConfigResponse ,
491+ )
475492} catch ( error ) {
476493this . storage . writeToCoderOutputChannel ( `Failed to configure SSH:${ error } ` )
477494throw error
@@ -503,6 +520,20 @@ export class Remote {
503520
504521this . storage . writeToCoderOutputChannel ( "Remote setup complete" )
505522
523+ // If Coder Connect is available for this workspace, switch to that
524+ const coderConnectAddr = await maybeCoderConnectAddr (
525+ agent . name ,
526+ parts . workspace ,
527+ parts . username ,
528+ sshConfigResponse . hostname_suffix ,
529+ )
530+ if ( coderConnectAddr ) {
531+ await vscode . commands . executeCommand ( "vscode.newWindow" , {
532+ remoteAuthority :`ssh-remote+${ coderConnectAddr } ` ,
533+ reuseWindow :true ,
534+ } )
535+ }
536+
506537// Returning the URL and token allows the plugin to authenticate its own
507538// client, for example to display the list of workspaces belonging to this
508539// deployment in the sidebar. We use our own client in here for reasons
@@ -550,30 +581,8 @@ export class Remote {
550581binaryPath :string ,
551582logDir :string ,
552583featureSet :FeatureSet ,
584+ sshConfigResponse :SSHConfigResponse ,
553585) {
554- let deploymentSSHConfig = { }
555- try {
556- const deploymentConfig = await restClient . getDeploymentSSHConfig ( )
557- deploymentSSHConfig = deploymentConfig . ssh_config_options
558- } catch ( error ) {
559- if ( ! isAxiosError ( error ) ) {
560- throw error
561- }
562- switch ( error . response ?. status ) {
563- case 404 :{
564- // Deployment does not support overriding ssh config yet. Likely an
565- // older version, just use the default.
566- break
567- }
568- case 401 :{
569- await this . vscodeProposed . window . showErrorMessage ( "Your session expired..." )
570- throw error
571- }
572- default :
573- throw error
574- }
575- }
576-
577586// deploymentConfig is now set from the remote coderd deployment.
578587// Now override with the user's config.
579588const userConfigSSH = vscode . workspace . getConfiguration ( "coder" ) . get < string [ ] > ( "sshConfig" ) || [ ]
@@ -596,7 +605,7 @@ export class Remote {
596605} ,
597606{ } as Record < string , string > ,
598607)
599- const sshConfigOverrides = mergeSSHConfigValues ( deploymentSSHConfig , userConfig )
608+ const sshConfigOverrides = mergeSSHConfigValues ( sshConfigResponse . ssh_config_options , userConfig )
600609
601610let sshConfigFile = vscode . workspace . getConfiguration ( ) . get < string > ( "remote.SSH.configFile" )
602611if ( ! sshConfigFile ) {