server.go

 1// Package acp implements the Agent-Client Protocol server for Crush.
 2//
 3// ACP allows external clients (web, desktop, mobile) to drive Crush as an
 4// agent server over stdio using JSON-RPC.
 5package acp
 6
 7import (
 8	"context"
 9	"log/slog"
10	"os"
11	"os/signal"
12	"syscall"
13
14	"github.com/coder/acp-go-sdk"
15)
16
17// Server manages the ACP connection lifecycle.
18type Server struct {
19	ctx    context.Context
20	cancel context.CancelFunc
21	agent  *Agent
22}
23
24// NewServer creates a new ACP server.
25func NewServer(ctx context.Context) *Server {
26	ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, os.Kill, syscall.SIGTERM)
27	return &Server{
28		ctx:    ctx,
29		cancel: cancel,
30	}
31}
32
33// Run starts the ACP server and blocks until the connection closes.
34func (s *Server) Run(agent *Agent) error {
35	s.agent = agent
36	slog.Info("Starting ACP server")
37
38	conn := acp.NewAgentSideConnection(agent, os.Stdout, os.Stdin)
39	conn.SetLogger(slog.Default())
40	agent.SetAgentConnection(conn)
41
42	select {
43	case <-conn.Done():
44		slog.Debug("ACP client disconnected")
45	case <-s.ctx.Done():
46		slog.Debug("ACP server received shutdown signal")
47	}
48
49	return nil
50}
51
52// Shutdown performs graceful shutdown.
53func (s *Server) Shutdown() {
54	s.cancel()
55}