@@ -977,7 +977,7 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
977977)
978978
979979// Check if subagent already exists for this devcontainer.
980- recreateSubAgent := false
980+ maybeRecreateSubAgent := false
981981proc ,injected := api .injectedSubAgentProcs [dc .WorkspaceFolder ]
982982if injected {
983983if proc .containerID == container .ID && proc .ctx .Err ()== nil {
@@ -992,12 +992,15 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
992992logger .Debug (ctx ,"container ID changed, injecting subagent into new container" ,
993993slog .F ("old_container_id" ,proc .containerID ),
994994)
995- recreateSubAgent = true
995+ maybeRecreateSubAgent = true
996996}
997997
998998// Container ID changed or the subagent process is not running,
999999// stop the existing subagent context to replace it.
10001000proc .stop ()
1001+ }else {
1002+ // Set SubAgent defaults.
1003+ proc .agent .OperatingSystem = "linux" // Assuming Linux for devcontainers.
10011004}
10021005
10031006// Prepare the subAgentProcess to be used when running the subagent.
@@ -1090,36 +1093,33 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
10901093// logger.Warn(ctx, "set CAP_NET_ADMIN on agent binary failed", slog.Error(err))
10911094// }
10921095
1096+ updatedSubAgent := proc .agent
1097+
10931098// Detect workspace folder by executing `pwd` in the container.
10941099// NOTE(mafredri): This is a quick and dirty way to detect the
10951100// workspace folder inside the container. In the future we will
10961101// rely more on `devcontainer read-configuration`.
1097- var pwdBuf bytes.Buffer
1098- err = api .dccli .Exec (ctx ,dc .WorkspaceFolder ,dc .ConfigPath ,"pwd" , []string {},
1099- WithExecOutput (& pwdBuf ,io .Discard ),
1100- WithExecContainerID (container .ID ),
1101- )
1102- if err != nil {
1103- return xerrors .Errorf ("check workspace folder in container: %w" ,err )
1104- }
1105- directory := strings .TrimSpace (pwdBuf .String ())
1106- if directory == "" {
1107- logger .Warn (ctx ,"detected workspace folder is empty, using default workspace folder" ,
1108- slog .F ("default_workspace_folder" ,DevcontainerDefaultContainerWorkspaceFolder ),
1102+ if proc .agent .Directory == "" || maybeRecreateSubAgent {
1103+ var pwdBuf bytes.Buffer
1104+ err = api .dccli .Exec (ctx ,dc .WorkspaceFolder ,dc .ConfigPath ,"pwd" , []string {},
1105+ WithExecOutput (& pwdBuf ,io .Discard ),
1106+ WithExecContainerID (container .ID ),
11091107)
1110- directory = DevcontainerDefaultContainerWorkspaceFolder
1111- }
1112-
1113- if proc .agent .ID != uuid .Nil && recreateSubAgent {
1114- logger .Debug (ctx ,"deleting existing subagent for recreation" ,slog .F ("agent_id" ,proc .agent .ID ))
1115- client := * api .subAgentClient .Load ()
1116- err = client .Delete (ctx ,proc .agent .ID )
11171108if err != nil {
1118- return xerrors .Errorf ("delete existing subagent failed: %w" ,err )
1109+ return xerrors .Errorf ("check workspace folder in container: %w" ,err )
1110+ }
1111+ directory := strings .TrimSpace (pwdBuf .String ())
1112+ if directory == "" {
1113+ logger .Warn (ctx ,"detected workspace folder is empty, using default workspace folder" ,
1114+ slog .F ("default_workspace_folder" ,DevcontainerDefaultContainerWorkspaceFolder ),
1115+ )
1116+ directory = DevcontainerDefaultContainerWorkspaceFolder
11191117}
1120- proc .agent = SubAgent {}
1118+
1119+ updatedSubAgent .Directory = directory
11211120}
1122- if proc .agent .ID == uuid .Nil {
1121+
1122+ if maybeRecreateSubAgent {
11231123displayAppsMap := map [codersdk.DisplayApp ]bool {
11241124// NOTE(DanielleMaywood):
11251125// We use the same defaults here as set in terraform-provider-coder.
@@ -1138,6 +1138,9 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
11381138
11391139for _ ,customization := range coderCustomization {
11401140for app ,enabled := range customization .DisplayApps {
1141+ if _ ,ok := displayAppsMap [app ];! ok {
1142+ continue // Ignore unknown display apps.
1143+ }
11411144displayAppsMap [app ]= enabled
11421145}
11431146}
@@ -1149,24 +1152,37 @@ func (api *API) maybeInjectSubAgentIntoContainerLocked(ctx context.Context, dc c
11491152displayApps = append (displayApps ,app )
11501153}
11511154}
1155+ slices .Sort (displayApps )
1156+
1157+ updatedSubAgent .Name = dc .Name
1158+ updatedSubAgent .DisplayApps = displayApps
1159+ }
1160+
1161+ recreateSubAgent := maybeRecreateSubAgent && ! proc .agent .Equal (updatedSubAgent )
1162+ if recreateSubAgent {
1163+ logger .Debug (ctx ,"deleting existing subagent for recreation" ,slog .F ("agent_id" ,proc .agent .ID ))
1164+ client := * api .subAgentClient .Load ()
1165+ err = client .Delete (ctx ,proc .agent .ID )
1166+ if err != nil {
1167+ return xerrors .Errorf ("delete existing subagent failed: %w" ,err )
1168+ }
1169+ proc .agent = SubAgent {}// In case of error, make sure this is cleared.
1170+
1171+ // Reset fields that are not part of the request.
1172+ updatedSubAgent .ID = uuid .Nil
1173+ updatedSubAgent .AuthToken = uuid .Nil
11521174
11531175logger .Debug (ctx ,"creating new subagent" ,
1154- slog .F ("directory" ,directory ),
1155- slog .F ("display_apps" ,displayApps ),
1176+ slog .F ("directory" ,updatedSubAgent . Directory ),
1177+ slog .F ("display_apps" ,updatedSubAgent . DisplayApps ),
11561178)
11571179
11581180// Create new subagent record in the database to receive the auth token.
1159- client := * api .subAgentClient .Load ()
1160- proc .agent ,err = client .Create (ctx ,SubAgent {
1161- Name :dc .Name ,
1162- Directory :directory ,
1163- OperatingSystem :"linux" ,// Assuming Linux for devcontainers.
1164- Architecture :arch ,
1165- DisplayApps :displayApps ,
1166- })
1181+ newSubAgent ,err := client .Create (ctx ,updatedSubAgent )
11671182if err != nil {
11681183return xerrors .Errorf ("create subagent failed: %w" ,err )
11691184}
1185+ proc .agent = newSubAgent
11701186
11711187logger .Info (ctx ,"created new subagent" ,slog .F ("agent_id" ,proc .agent .ID ))
11721188}