run.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package cmd
  2. import (
  3. "context"
  4. "fmt"
  5. "log/slog"
  6. "os"
  7. "os/signal"
  8. "strings"
  9. "charm.land/log/v2"
  10. "github.com/charmbracelet/crush/internal/event"
  11. "github.com/spf13/cobra"
  12. )
  13. var runCmd = &cobra.Command{
  14. Use: "run [prompt...]",
  15. Short: "Run a single non-interactive prompt",
  16. Long: `Run a single prompt in non-interactive mode and exit.
  17. The prompt can be provided as arguments or piped from stdin.`,
  18. Example: `
  19. # Run a simple prompt
  20. crush run Explain the use of context in Go
  21. # Pipe input from stdin
  22. curl https://charm.land | crush run "Summarize this website"
  23. # Read from a file
  24. crush run "What is this code doing?" <<< prrr.go
  25. # Run in quiet mode (hide the spinner)
  26. crush run --quiet "Generate a README for this project"
  27. # Run in verbose mode
  28. crush run --verbose "Generate a README for this project"
  29. `,
  30. RunE: func(cmd *cobra.Command, args []string) error {
  31. quiet, _ := cmd.Flags().GetBool("quiet")
  32. verbose, _ := cmd.Flags().GetBool("verbose")
  33. largeModel, _ := cmd.Flags().GetString("model")
  34. smallModel, _ := cmd.Flags().GetString("small-model")
  35. // Cancel on SIGINT or SIGTERM.
  36. ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
  37. defer cancel()
  38. app, err := setupApp(cmd)
  39. if err != nil {
  40. return err
  41. }
  42. defer app.Shutdown()
  43. if !app.Config().IsConfigured() {
  44. return fmt.Errorf("no providers configured - please run 'crush' to set up a provider interactively")
  45. }
  46. if verbose {
  47. slog.SetDefault(slog.New(log.New(os.Stderr)))
  48. }
  49. prompt := strings.Join(args, " ")
  50. prompt, err = MaybePrependStdin(prompt)
  51. if err != nil {
  52. slog.Error("Failed to read from stdin", "error", err)
  53. return err
  54. }
  55. if prompt == "" {
  56. return fmt.Errorf("no prompt provided")
  57. }
  58. event.SetNonInteractive(true)
  59. event.AppInitialized()
  60. return app.RunNonInteractive(ctx, os.Stdout, prompt, largeModel, smallModel, quiet || verbose)
  61. },
  62. PostRun: func(cmd *cobra.Command, args []string) {
  63. event.AppExited()
  64. },
  65. }
  66. func init() {
  67. runCmd.Flags().BoolP("quiet", "q", false, "Hide spinner")
  68. runCmd.Flags().BoolP("verbose", "v", false, "Show logs")
  69. runCmd.Flags().StringP("model", "m", "", "Model to use. Accepts 'model' or 'provider/model' to disambiguate models with the same name across providers")
  70. runCmd.Flags().String("small-model", "", "Small model to use. If not provided, uses the default small model for the provider")
  71. }