// Package config parses the command-line configuration of the ori server. // // It is deliberately tiny: three flags, validated once at startup, then passed // around as an immutable value. package config import ( "flag" "fmt" "os" "path/filepath" "strings" ) // DefaultAgentCommand is the ACP agent spawned when --agent-cmd is not given. // It is the Agent Client Protocol project's adapter for the Claude Agent SDK, // which bundles a current Claude Code CLI (the older Zed adapter ships a CLI // too old for current models). const DefaultAgentCommand = "npx -y @agentclientprotocol/claude-agent-acp" // Config holds the runtime configuration of the ori server. type Config struct { // Addr is the TCP address the HTTP server listens on, e.g. ":8888". Addr string // Cwd is the absolute working directory handed to the agent session. Cwd string // AgentCommand is the command line used to spawn the ACP agent, // split on whitespace (the first field is the executable). AgentCommand []string } // FromArgs parses command-line arguments (without the program name) into a // Config. It returns an error for unknown flags, an empty agent command, or a // working directory that does not exist. // // Example: // // cfg, err := config.FromArgs([]string{"--addr", ":9000", "--cwd", "/tmp"}) // if err != nil { // log.Fatal(err) // } // fmt.Println(cfg.Addr) // ":9000" func FromArgs(args []string) (Config, error) { fs := flag.NewFlagSet("ori", flag.ContinueOnError) addr := fs.String("addr", ":8888", "TCP address the HTTP server listens on") cwd := fs.String("cwd", "", "working directory for the agent session (default: current directory)") agentCmd := fs.String("agent-cmd", DefaultAgentCommand, "command spawning the ACP agent, split on whitespace") if err := fs.Parse(args); err != nil { return Config{}, err } command := strings.Fields(*agentCmd) if len(command) == 0 { return Config{}, fmt.Errorf("--agent-cmd must not be empty") } dir := *cwd if dir == "" { wd, err := os.Getwd() if err != nil { return Config{}, fmt.Errorf("resolve current directory: %w", err) } dir = wd } absDir, err := filepath.Abs(dir) if err != nil { return Config{}, fmt.Errorf("resolve --cwd: %w", err) } info, err := os.Stat(absDir) if err != nil { return Config{}, fmt.Errorf("--cwd: %w", err) } if !info.IsDir() { return Config{}, fmt.Errorf("--cwd: %s is not a directory", absDir) } return Config{Addr: *addr, Cwd: absDir, AgentCommand: command}, nil }