10 tea "github.com/charmbracelet/bubbletea/v2"
11 "github.com/charmbracelet/crush/internal/app"
12 "github.com/charmbracelet/crush/internal/config"
13 "github.com/charmbracelet/crush/internal/db"
14 "github.com/charmbracelet/crush/internal/tui"
15 "github.com/charmbracelet/crush/internal/version"
16 "github.com/charmbracelet/fang"
17 "github.com/charmbracelet/x/term"
18 "github.com/spf13/cobra"
22 rootCmd.PersistentFlags().StringP("cwd", "c", "", "Current working directory")
23 rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug")
25 rootCmd.Flags().BoolP("help", "h", false, "Help")
26 rootCmd.Flags().BoolP("yolo", "y", false, "Automatically accept all permissions (dangerous mode)")
28 rootCmd.AddCommand(runCmd)
31var rootCmd = &cobra.Command{
33 Short: "Terminal-based AI assistant for software development",
34 Long: `Crush is a powerful terminal-based AI assistant that helps with software development tasks.
35It provides an interactive chat interface with AI capabilities, code analysis, and LSP integration
36to assist developers in writing, debugging, and understanding code directly from the terminal.`,
38# Run in interactive mode
41# Run with debug logging
44# Run with debug logging in a specific directory
45crush -d -c /path/to/project
50# Run a single non-interactive prompt
51crush run "Explain the use of context in Go"
53# Run in dangerous mode (auto-accept all permissions)
56 RunE: func(cmd *cobra.Command, args []string) error {
57 app, err := setupApp(cmd)
64 program := tea.NewProgram(
67 tea.WithContext(cmd.Context()),
68 tea.WithMouseCellMotion(), // Use cell motion instead of all motion to reduce event flooding
69 tea.WithFilter(tui.MouseEventFilter), // Filter mouse events based on focus state
72 go app.Subscribe(program)
74 if _, err := program.Run(); err != nil {
75 slog.Error("TUI run error", "error", err)
76 return fmt.Errorf("TUI error: %v", err)
83 if err := fang.Execute(
86 fang.WithVersion(version.Version),
87 fang.WithNotifySignal(os.Interrupt),
93// setupApp handles the common setup logic for both interactive and non-interactive modes.
94// It returns the app instance, config, cleanup function, and any error.
95func setupApp(cmd *cobra.Command) (*app.App, error) {
96 debug, _ := cmd.Flags().GetBool("debug")
97 yolo, _ := cmd.Flags().GetBool("yolo")
100 cwd, err := ResolveCwd(cmd)
105 cfg, err := config.Init(cwd, debug)
110 if cfg.Permissions == nil {
111 cfg.Permissions = &config.Permissions{}
113 cfg.Permissions.SkipRequests = yolo
115 // Connect to DB; this will also run migrations.
116 conn, err := db.Connect(ctx, cfg.Options.DataDirectory)
121 appInstance, err := app.New(ctx, conn, cfg)
123 slog.Error("Failed to create app instance", "error", err)
127 return appInstance, nil
130func MaybePrependStdin(prompt string) (string, error) {
131 if term.IsTerminal(os.Stdin.Fd()) {
134 fi, err := os.Stdin.Stat()
138 if fi.Mode()&os.ModeNamedPipe == 0 {
141 bts, err := io.ReadAll(os.Stdin)
145 return string(bts) + "\n\n" + prompt, nil
148func ResolveCwd(cmd *cobra.Command) (string, error) {
149 cwd, _ := cmd.Flags().GetString("cwd")
153 return "", fmt.Errorf("failed to change directory: %v", err)
157 cwd, err := os.Getwd()
159 return "", fmt.Errorf("failed to get current working directory: %v", err)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list