1package cmd
2
3import (
4 "fmt"
5 "log/slog"
6 "os"
7 "strings"
8
9 "github.com/spf13/cobra"
10)
11
12var runCmd = &cobra.Command{
13 Use: "run [prompt...]",
14 Short: "Run a single non-interactive prompt",
15 Long: `Run a single prompt in non-interactive mode and exit.
16The prompt can be provided as arguments or piped from stdin.`,
17 Example: `
18# Run a simple prompt
19crush run Explain the use of context in Go
20
21# Pipe input from stdin
22curl https://charm.land | crush run "Summarize this website"
23
24# Read from a file
25crush run "What is this code doing?" <<< prrr.go
26
27# Run in quiet mode (hide the spinner)
28crush run --quiet "Generate a README for this project"
29 `,
30 RunE: func(cmd *cobra.Command, args []string) error {
31 quiet, _ := cmd.Flags().GetBool("quiet")
32
33 app, err := setupApp(cmd)
34 if err != nil {
35 return err
36 }
37 defer app.Shutdown()
38
39 if !app.Config().IsConfigured() {
40 return fmt.Errorf("no providers configured - please run 'crush' to set up a provider interactively")
41 }
42
43 prompt := strings.Join(args, " ")
44
45 prompt, err = MaybePrependStdin(prompt)
46 if err != nil {
47 slog.Error("Failed to read from stdin", "error", err)
48 return err
49 }
50
51 if prompt == "" {
52 return fmt.Errorf("no prompt provided")
53 }
54
55 // TODO: Make this work when redirected to something other than stdout.
56 // For example:
57 // crush run "Do something fancy" > output.txt
58 // echo "Do something fancy" | crush run > output.txt
59 //
60 // TODO: We currently need to press ^c twice to cancel. Fix that.
61 return app.RunNonInteractive(cmd.Context(), os.Stdout, prompt, quiet)
62 },
63}
64
65func init() {
66 runCmd.Flags().BoolP("quiet", "q", false, "Hide spinner")
67}