diff --git a/go.mod b/go.mod index 3656cd8..933f241 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,12 @@ module runix go 1.23.8 + +require ( + github.com/briandowns/spinner v1.22.0 // indirect + github.com/fatih/color v1.7.0 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect + github.com/mattn/go-isatty v0.0.8 // indirect + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect + golang.org/x/term v0.1.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ef30e8b --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/briandowns/spinner v1.22.0 h1:fJ/7tyeM2q9ebM57kGfjnUSrgPJBsULk+/s61UpMGrw= +github.com/briandowns/spinner v1.22.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/go/cli/commands/commands.go b/go/cli/commands/commands.go new file mode 100644 index 0000000..bca7af7 --- /dev/null +++ b/go/cli/commands/commands.go @@ -0,0 +1,133 @@ +package commands + +import ( + "bufio" + "flag" + "fmt" + "os" + "strings" + "time" + + "github.com/briandowns/spinner" + "runix/go/openrouter" +) + +// Execute parses CLI arguments and dispatches to subcommands. +func Execute() { + if len(os.Args) < 2 { + usage() + return + } + + switch os.Args[1] { + case "chat": + chatCmd(os.Args[2:]) + case "create": + createCmd(os.Args[2:]) + case "demo": + demoCmd(os.Args[2:]) + default: + fmt.Println("Unknown command:", os.Args[1]) + usage() + } +} + +func usage() { + fmt.Println("Runix CLI") + fmt.Println("Usage:") + fmt.Println(" runix chat [options] ") + fmt.Println(" runix create ") + fmt.Println(" runix demo") +} + +// chatCmd sends a single message to the OpenRouter API. +func chatCmd(args []string) { + fs := flag.NewFlagSet("chat", flag.ExitOnError) + context := fs.String("context", "", "context prompt") + model := fs.String("model", "mistralai/mistral-small-3.2-24b-instruct:free", "model") + fs.Parse(args) + + if fs.NArg() < 1 { + fmt.Println("message is required") + return + } + + apiKey := os.Getenv("OPENROUTER_API_KEY") + if apiKey == "" { + fmt.Println("OPENROUTER_API_KEY environment variable not set") + return + } + + client := openrouter.NewClient(apiKey) + animate("generando respuesta") + reply, err := client.Chat(*model, *context, fs.Arg(0)) + if err != nil { + fmt.Println("error:", err) + return + } + chat("runix", reply) +} + +func createCmd(args []string) { + if len(args) < 1 { + fmt.Println("directory path is required") + return + } + path := args[0] + if err := os.MkdirAll(path, 0755); err != nil { + fmt.Println("error creating directory:", err) + return + } + fmt.Println("created directory", path) +} + +// demoCmd provides an interactive chat loop with animated output. +func demoCmd(args []string) { + fs := flag.NewFlagSet("demo", flag.ExitOnError) + context := fs.String("context", "", "context prompt") + model := fs.String("model", "mistralai/mistral-small-3.2-24b-instruct:free", "model") + fs.Parse(args) + + apiKey := os.Getenv("OPENROUTER_API_KEY") + if apiKey == "" { + fmt.Println("OPENROUTER_API_KEY environment variable not set") + return + } + + client := openrouter.NewClient(apiKey) + scanner := bufio.NewScanner(os.Stdin) + fmt.Println("Escribe 'exit' para terminar la conversación.") + for { + fmt.Print(":user: ") + if !scanner.Scan() { + break + } + msg := strings.TrimSpace(scanner.Text()) + if msg == "" { + continue + } + if strings.ToLower(msg) == "exit" { + break + } + animate("generando respuesta") + reply, err := client.Chat(*model, *context, msg) + if err != nil { + fmt.Println("error:", err) + continue + } + chat("runix", reply) + } +} + +func chat(role, msg string) { + fmt.Printf(":%s: %s\n", role, msg) +} + +func animate(action string) { + s := spinner.New(spinner.CharSets[14], 100*time.Millisecond) + s.Suffix = " " + action + s.Start() + time.Sleep(1 * time.Second) + s.Stop() + fmt.Printf("............... %s\n", action) +} diff --git a/go/cli/main.go b/go/cli/main.go index 7afe27d..f72b60b 100644 --- a/go/cli/main.go +++ b/go/cli/main.go @@ -1,72 +1,7 @@ package main -import ( - "flag" - "fmt" - "os" - - "runix/go/openrouter" -) +import "runix/go/cli/commands" func main() { - if len(os.Args) < 2 { - usage() - return - } - - switch os.Args[1] { - case "chat": - chatCmd(os.Args[2:]) - case "create": - createCmd(os.Args[2:]) - default: - fmt.Println("Unknown command:", os.Args[1]) - usage() - } -} - -func usage() { - fmt.Println("Runix CLI") - fmt.Println("Usage:") - fmt.Println(" runix chat [options] ") - fmt.Println(" runix create ") -} - -func chatCmd(args []string) { - fs := flag.NewFlagSet("chat", flag.ExitOnError) - context := fs.String("context", "", "context prompt") - model := fs.String("model", "mistralai/mistral-small-3.2-24b-instruct:free", "model") - fs.Parse(args) - - if fs.NArg() < 1 { - fmt.Println("message is required") - return - } - - apiKey := os.Getenv("OPENROUTER_API_KEY") - if apiKey == "" { - fmt.Println("OPENROUTER_API_KEY environment variable not set") - return - } - - client := openrouter.NewClient(apiKey) - reply, err := client.Chat(*model, *context, fs.Arg(0)) - if err != nil { - fmt.Println("error:", err) - return - } - fmt.Println(reply) -} - -func createCmd(args []string) { - if len(args) < 1 { - fmt.Println("directory path is required") - return - } - path := args[0] - if err := os.MkdirAll(path, 0755); err != nil { - fmt.Println("error creating directory:", err) - return - } - fmt.Println("created directory", path) + commands.Execute() }