@@ -40,6 +40,7 @@ import (
4040 "github.com/coder/coder/v2/agent/agentcontainers"
4141 "github.com/coder/coder/v2/agent/agentexec"
4242 "github.com/coder/coder/v2/agent/agentscripts"
43+ "github.com/coder/coder/v2/agent/agentsocket"
4344 "github.com/coder/coder/v2/agent/agentssh"
4445 "github.com/coder/coder/v2/agent/proto"
4546 "github.com/coder/coder/v2/agent/proto/resourcesmonitor"
@@ -91,6 +92,7 @@ type Options struct {
9192 Devcontainers bool
9293 DevcontainerAPIOptions []agentcontainers.Option // Enable Devcontainers for these to be effective.
9394 Clock quartz.Clock
95+ SocketPath string // Path for the agent socket server
9496}
9597
9698type Client interface {
@@ -190,6 +192,7 @@ func New(options Options) Agent {
190192
191193 devcontainers : options .Devcontainers ,
192194 containerAPIOptions : options .DevcontainerAPIOptions ,
195+ socketPath : options .SocketPath ,
193196 }
194197 // Initially, we have a closed channel, reflecting the fact that we are not initially connected.
195198 // Each time we connect we replace the channel (while holding the closeMutex) with a new one
@@ -271,6 +274,9 @@ type agent struct {
271274 devcontainers bool
272275 containerAPIOptions []agentcontainers.Option
273276 containerAPI * agentcontainers.API
277+
278+ socketPath string
279+ socketServer * agentsocket.Server
274280}
275281
276282func (a * agent ) TailnetConn () * tailnet.Conn {
@@ -350,9 +356,35 @@ func (a *agent) init() {
350356 s .ExperimentalContainers = a .devcontainers
351357 },
352358 )
359+
360+ a .initSocketServer ()
361+
353362 go a .runLoop ()
354363}
355364
365+ // initSocketServer initializes server that allows direct communication with a workspace agent using IPC.
366+ func (a * agent ) initSocketServer () {
367+ if a .socketPath == "" {
368+ a .logger .Info (a .hardCtx , "socket server disabled (no path configured)" )
369+ return
370+ }
371+
372+ server , err := agentsocket .NewServer (a .socketPath , a .logger .Named ("socket" ))
373+ if err != nil {
374+ a .logger .Warn (a .hardCtx , "failed to create socket server" , slog .Error (err ))
375+ return
376+ }
377+
378+ err = server .Start ()
379+ if err != nil {
380+ a .logger .Warn (a .hardCtx , "failed to start socket server" , slog .Error (err ))
381+ return
382+ }
383+
384+ a .socketServer = server
385+ a .logger .Debug (a .hardCtx , "socket server started" , slog .F ("path" , a .socketPath ))
386+ }
387+
356388// runLoop attempts to start the agent in a retry loop.
357389// Coder may be offline temporarily, a connection issue
358390// may be happening, but regardless after the intermittent
@@ -1920,6 +1952,13 @@ func (a *agent) Close() error {
19201952 lifecycleState = codersdk .WorkspaceAgentLifecycleShutdownError
19211953 }
19221954 }
1955+
1956+ if a .socketServer != nil {
1957+ if err := a .socketServer .Stop (); err != nil {
1958+ a .logger .Error (a .hardCtx , "socket server close" , slog .Error (err ))
1959+ }
1960+ }
1961+
19231962 a .setLifecycle (lifecycleState )
19241963
19251964 err = a .scriptRunner .Close ()
0 commit comments