2026-04-18 14:08:01 +00:00
package main
import (
"context"
"fmt"
"log/slog"
"os"
"time"
"github.com/spf13/cobra"
"github.com/daniel/cursor-adapter/internal/bridge"
"github.com/daniel/cursor-adapter/internal/config"
"github.com/daniel/cursor-adapter/internal/server"
)
var (
configPath string
port int
debug bool
useACP bool
chatOnlySet bool
chatOnlyFlag bool
)
func main ( ) {
rootCmd := & cobra . Command {
Use : "cursor-adapter" ,
Short : "OpenAI-compatible proxy for Cursor CLI" ,
RunE : run ,
}
rootCmd . Flags ( ) . StringVarP ( & configPath , "config" , "c" , "" , "config file path (default: ~/.cursor-adapter/config.yaml)" )
rootCmd . Flags ( ) . IntVarP ( & port , "port" , "p" , 0 , "server port (overrides config)" )
rootCmd . Flags ( ) . BoolVar ( & debug , "debug" , false , "enable debug logging" )
rootCmd . Flags ( ) . BoolVar ( & useACP , "use-acp" , false , "use Cursor ACP transport instead of CLI stream-json" )
rootCmd . Flags ( ) . BoolVar ( & chatOnlyFlag , "chat-only-workspace" , true , "isolate Cursor CLI in an empty temp workspace with overridden HOME/CURSOR_CONFIG_DIR (set to false to let Cursor agent see the adapter's cwd)" )
rootCmd . PreRun = func ( cmd * cobra . Command , args [ ] string ) {
chatOnlySet = cmd . Flags ( ) . Changed ( "chat-only-workspace" )
}
if err := rootCmd . Execute ( ) ; err != nil {
os . Exit ( 1 )
}
}
func run ( cmd * cobra . Command , args [ ] string ) error {
var logLevel slog . Level
if debug {
logLevel = slog . LevelDebug
} else {
logLevel = slog . LevelInfo
}
logger := slog . New ( slog . NewTextHandler ( os . Stderr , & slog . HandlerOptions { Level : logLevel } ) )
slog . SetDefault ( logger )
cfg , err := config . Load ( configPath )
if err != nil {
return fmt . Errorf ( "load config: %w" , err )
}
if port > 0 {
cfg . Port = port
}
if useACP {
cfg . UseACP = true
}
if chatOnlySet {
cfg . ChatOnlyWorkspace = chatOnlyFlag
}
2026-04-25 13:18:22 +00:00
br := bridge . NewBridge ( bridge . Options {
CursorPath : cfg . CursorCLIPath ,
Logger : logger ,
UseACP : cfg . UseACP ,
ChatOnly : cfg . ChatOnlyWorkspace ,
MaxConcurrent : cfg . MaxConcurrent ,
Timeout : time . Duration ( cfg . Timeout ) * time . Second ,
Mode : cfg . CursorMode ,
WorkspaceRoot : cfg . WorkspaceRoot ,
} )
2026-04-18 14:08:01 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
if err := br . CheckHealth ( ctx ) ; err != nil {
return fmt . Errorf ( "cursor cli not available: %w" , err )
}
logger . Info ( "Cursor CLI OK" )
srv := server . New ( cfg , br )
mode := "CLI"
if cfg . UseACP {
mode = "ACP"
}
logger . Info ( "Starting cursor-adapter" ,
"port" , cfg . Port ,
2026-04-25 13:18:22 +00:00
"transport" , mode ,
"cursor_mode" , cfg . CursorMode ,
"workspace_root" , cfg . WorkspaceRoot ,
2026-04-18 14:08:01 +00:00
"chat_only_workspace" , cfg . ChatOnlyWorkspace ,
)
return srv . Run ( )
}