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 } br := bridge.NewBridge( cfg.CursorCLIPath, logger, cfg.UseACP, cfg.ChatOnlyWorkspace, cfg.MaxConcurrent, time.Duration(cfg.Timeout)*time.Second, ) 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, "mode", mode, "chat_only_workspace", cfg.ChatOnlyWorkspace, ) return srv.Run() }