run.go

 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}