package main import ( "context" "errors" "flag" "log" "net" "net/http" "os" "os/signal" "syscall" "time" ) type bridge struct { binary string dir string mcpURL string } func main() { if err := run(); err != nil { log.Print(err) os.Exit(1) } } func run() error { b := &bridge{} addr := flag.String("listen", "127.0.0.1:8080", "HTTP listen address") flag.StringVar(&b.binary, "codex", "codex", "Codex executable") flag.StringVar(&b.dir, "workdir", ".", "Codex working directory") flag.StringVar(&b.mcpURL, "mcp-url", "", "AgentGateway MCP endpoint; otherwise use Codex configuration") flag.Parse() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() s := &http.Server{Addr: *addr, Handler: b.handler(), ReadHeaderTimeout: 10 * time.Second, BaseContext: func(net.Listener) context.Context { return ctx }} stopped := make(chan error, 1) go func() { stopped <- s.ListenAndServe() }() var serveErr error select { case err := <-stopped: if !errors.Is(err, http.ErrServerClosed) { serveErr = err } case <-ctx.Done(): } stop() shutdown, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() return errors.Join(serveErr, s.Shutdown(shutdown)) } func (b *bridge) handler() http.Handler { mux := http.NewServeMux() mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }) mux.HandleFunc("GET /v1/models", b.models) mux.HandleFunc("POST /v1/chat/completions", b.chat) return mux }