on main help sign in
feat(permissions): add `--yolo` flag for auto-accepting all permissions
2d332fchems
cmd/root.go+6
@@ -45,6 +45,9 @@ to assist developers in writing, debugging, and understanding code directly from
45
45
46 # Run a single non-interactive prompt with JSON output format
46 # Run a single non-interactive prompt with JSON output format
47 crush -p "Explain the use of context in Go" -f json
47 crush -p "Explain the use of context in Go" -f json
48+
49+ # Run in dangerous mode (auto-accept all permissions)
50+ crush -y
48 `,
51 `,
49 RunE: func(cmd *cobra.Command, args []string) error {
52 RunE: func(cmd *cobra.Command, args []string) error {
50 // Load the config
53 // Load the config
@@ -52,6 +55,7 @@ to assist developers in writing, debugging, and understanding code directly from
52 cwd, _ := cmd.Flags().GetString("cwd")
55 cwd, _ := cmd.Flags().GetString("cwd")
53 prompt, _ := cmd.Flags().GetString("prompt")
56 prompt, _ := cmd.Flags().GetString("prompt")
54 quiet, _ := cmd.Flags().GetBool("quiet")
57 quiet, _ := cmd.Flags().GetBool("quiet")
58+ yolo, _ := cmd.Flags().GetBool("yolo")
55
59
56 if cwd != "" {
60 if cwd != "" {
57 err := os.Chdir(cwd)
61 err := os.Chdir(cwd)
@@ -71,6 +75,7 @@ to assist developers in writing, debugging, and understanding code directly from
71 if err != nil {
75 if err != nil {
72 return err
76 return err
73 }
77 }
78+ cfg.Options.SkipPermissionsRequests = yolo
74
79
75 ctx := cmd.Context()
80 ctx := cmd.Context()
76
81
@@ -152,6 +157,7 @@ func init() {
152 rootCmd.Flags().BoolP("help", "h", false, "Help")
157 rootCmd.Flags().BoolP("help", "h", false, "Help")
153 rootCmd.Flags().BoolP("debug", "d", false, "Debug")
158 rootCmd.Flags().BoolP("debug", "d", false, "Debug")
154 rootCmd.Flags().StringP("prompt", "p", "", "Prompt to run in non-interactive mode")
159 rootCmd.Flags().StringP("prompt", "p", "", "Prompt to run in non-interactive mode")
160+ rootCmd.Flags().BoolP("yolo", "y", false, "Automatically accept all permissions (dangerous mode)")
155
161
156 // Add quiet flag to hide spinner in non-interactive mode
162 // Add quiet flag to hide spinner in non-interactive mode
157 rootCmd.Flags().BoolP("quiet", "q", false, "Hide spinner in non-interactive mode")
163 rootCmd.Flags().BoolP("quiet", "q", false, "Hide spinner in non-interactive mode")
internal/app/app.go+2−1
@@ -58,12 +58,13 @@ func New(ctx context.Context, conn *sql.DB, cfg *config.Config) (*App, error) {
58 sessions := session.NewService(q)
58 sessions := session.NewService(q)
59 messages := message.NewService(q)
59 messages := message.NewService(q)
60 files := history.NewService(q, conn)
60 files := history.NewService(q, conn)
61+ skipPermissionsRequests := cfg.Options != nil && cfg.Options.SkipPermissionsRequests
61
62
62 app := &App{
63 app := &App{
63 Sessions: sessions,
64 Sessions: sessions,
64 Messages: messages,
65 Messages: messages,
65 History: files,
66 History: files,
66− Permissions: permission.NewPermissionService(cfg.WorkingDir()),
67+ Permissions: permission.NewPermissionService(cfg.WorkingDir(), skipPermissionsRequests),
67 LSPClients: make(map[string]*lsp.Client),
68 LSPClients: make(map[string]*lsp.Client),
68
69
69 globalCtx: ctx,
70 globalCtx: ctx,
internal/config/config.go+7−7
@@ -114,13 +114,13 @@ type TUIOptions struct {
114}
114}
115
115
116type Options struct {
116type Options struct {
117− ContextPaths []string `json:"context_paths,omitempty"`
117+ ContextPaths []string `json:"context_paths,omitempty"`
118− TUI *TUIOptions `json:"tui,omitempty"`
118+ TUI *TUIOptions `json:"tui,omitempty"`
119− Debug bool `json:"debug,omitempty"`
119+ Debug bool `json:"debug,omitempty"`
120− DebugLSP bool `json:"debug_lsp,omitempty"`
120+ DebugLSP bool `json:"debug_lsp,omitempty"`
121− DisableAutoSummarize bool `json:"disable_auto_summarize,omitempty"`
121+ DisableAutoSummarize bool `json:"disable_auto_summarize,omitempty"`
122− // Relative to the cwd
122+ DataDirectory string `json:"data_directory,omitempty"` // Relative to the cwd
123− DataDirectory string `json:"data_directory,omitempty"`
123+ SkipPermissionsRequests bool `json:"-"` // Automatically accept all permissions (YOLO mode)
124}
124}
125
125
126type MCPs map[string]MCPConfig
126type MCPs map[string]MCPConfig
internal/permission/permission.go+7−1
@@ -49,6 +49,7 @@ type permissionService struct {
49 pendingRequests sync.Map
49 pendingRequests sync.Map
50 autoApproveSessions []string
50 autoApproveSessions []string
51 autoApproveSessionsMu sync.RWMutex
51 autoApproveSessionsMu sync.RWMutex
52+ skip bool
52}
53}
53
54
54func (s *permissionService) GrantPersistent(permission PermissionRequest) {
55func (s *permissionService) GrantPersistent(permission PermissionRequest) {
@@ -77,6 +78,10 @@ func (s *permissionService) Deny(permission PermissionRequest) {
77}
78}
78
79
79func (s *permissionService) Request(opts CreatePermissionRequest) bool {
80func (s *permissionService) Request(opts CreatePermissionRequest) bool {
81+ if s.skip {
82+ return true
83+ }
84+
80 s.autoApproveSessionsMu.RLock()
85 s.autoApproveSessionsMu.RLock()
81 autoApprove := slices.Contains(s.autoApproveSessions, opts.SessionID)
86 autoApprove := slices.Contains(s.autoApproveSessions, opts.SessionID)
82 s.autoApproveSessionsMu.RUnlock()
87 s.autoApproveSessionsMu.RUnlock()
@@ -125,10 +130,11 @@ func (s *permissionService) AutoApproveSession(sessionID string) {
125 s.autoApproveSessionsMu.Unlock()
130 s.autoApproveSessionsMu.Unlock()
126}
131}
127
132
128−func NewPermissionService(workingDir string) Service {
133+func NewPermissionService(workingDir string, skip bool) Service {
129 return &permissionService{
134 return &permissionService{
130 Broker: pubsub.NewBroker[PermissionRequest](),
135 Broker: pubsub.NewBroker[PermissionRequest](),
131 workingDir: workingDir,
136 workingDir: workingDir,
132 sessionPermissions: make([]PermissionRequest, 0),
137 sessionPermissions: make([]PermissionRequest, 0),
138+ skip: skip,
133 }
139 }
134}
140}