on main help sign in
feat: add yolo mode command (#654)
a47d761Kujtim Hoxha
internal/permission/permission.go+10
@@ -49,6 +49,8 @@ type Service interface {
49 Deny(permission PermissionRequest)
49 Deny(permission PermissionRequest)
50 Request(opts CreatePermissionRequest) bool
50 Request(opts CreatePermissionRequest) bool
51 AutoApproveSession(sessionID string)
51 AutoApproveSession(sessionID string)
52+ SetSkipRequests(skip bool)
53+ SkipRequests() bool
52 SubscribeNotifications(ctx context.Context) <-chan pubsub.Event[PermissionNotification]
54 SubscribeNotifications(ctx context.Context) <-chan pubsub.Event[PermissionNotification]
53}
55}
54
56
@@ -210,6 +212,14 @@ func (s *permissionService) SubscribeNotifications(ctx context.Context) <-chan p
210 return s.notificationBroker.Subscribe(ctx)
212 return s.notificationBroker.Subscribe(ctx)
211}
213}
212
214
215+func (s *permissionService) SetSkipRequests(skip bool) {
216+ s.skip = skip
217+}
218+
219+func (s *permissionService) SkipRequests() bool {
220+ return s.skip
221+}
222+
213func NewPermissionService(workingDir string, skip bool, allowedTools []string) Service {
223func NewPermissionService(workingDir string, skip bool, allowedTools []string) Service {
214 return &permissionService{
224 return &permissionService{
215 Broker: pubsub.NewBroker[PermissionRequest](),
225 Broker: pubsub.NewBroker[PermissionRequest](),
internal/tui/components/chat/editor/editor.go+41−11
@@ -263,6 +263,9 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
263 Attachment: attachment,
263 Attachment: attachment,
264 })
264 })
265
265
266+ case commands.ToggleYoloModeMsg:
267+ m.setEditorPrompt()
268+ return m, nil
266 case tea.KeyPressMsg:
269 case tea.KeyPressMsg:
267 cur := m.textarea.Cursor()
270 cur := m.textarea.Cursor()
268 curIdx := m.textarea.Width()*cur.Y + cur.X
271 curIdx := m.textarea.Width()*cur.Y + cur.X
@@ -368,6 +371,14 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
368 return m, tea.Batch(cmds...)
371 return m, tea.Batch(cmds...)
369}
372}
370
373
374+func (m *editorCmp) setEditorPrompt() {
375+ if m.app.Permissions.SkipRequests() {
376+ m.textarea.SetPromptFunc(4, yoloPromptFunc)
377+ return
378+ }
379+ m.textarea.SetPromptFunc(4, normalPromptFunc)
380+}
381+
371func (m *editorCmp) completionsPosition() (int, int) {
382func (m *editorCmp) completionsPosition() (int, int) {
372 cur := m.textarea.Cursor()
383 cur := m.textarea.Cursor()
373 if cur == nil {
384 if cur == nil {
@@ -416,6 +427,9 @@ func (m *editorCmp) View() string {
416 } else {
427 } else {
417 m.textarea.Placeholder = m.readyPlaceholder
428 m.textarea.Placeholder = m.readyPlaceholder
418 }
429 }
430+ if m.app.Permissions.SkipRequests() {
431+ m.textarea.Placeholder = "Yolo mode!"
432+ }
419 if len(m.attachments) == 0 {
433 if len(m.attachments) == 0 {
420 content := t.S().Base.Padding(1).Render(
434 content := t.S().Base.Padding(1).Render(
421 m.textarea.View(),
435 m.textarea.View(),
@@ -529,31 +543,47 @@ func (c *editorCmp) HasAttachments() bool {
529 return len(c.attachments) > 0
543 return len(c.attachments) > 0
530}
544}
531
545
532−func New(app *app.App) Editor {
546+func normalPromptFunc(info textarea.PromptInfo) string {
533 t := styles.CurrentTheme()
547 t := styles.CurrentTheme()
534− ta := textarea.New()
548+ if info.LineNumber == 0 {
535− ta.SetStyles(t.S().TextArea)
549+ return " > "
550+ }
551+ if info.Focused {
552+ return t.S().Base.Foreground(t.GreenDark).Render("::: ")
553+ }
554+ return t.S().Muted.Render("::: ")
555+}
556+
536− ta.SetPromptFunc(4, func(info textarea.PromptInfo) string {
557+func yoloPromptFunc(info textarea.PromptInfo) string {
558+ t := styles.CurrentTheme()
537− if info.LineNumber == 0 {
559+ if info.LineNumber == 0 {
538− return " > "
539− }
540 if info.Focused {
560 if info.Focused {
541− return t.S().Base.Foreground(t.GreenDark).Render("::: ")
561+ return fmt.Sprintf("%s ", t.YoloIconFocused)
542 } else {
562 } else {
543− return t.S().Muted.Render("::: ")
563+ return fmt.Sprintf("%s ", t.YoloIconBlurred)
544 }
564 }
545− })
565+ }
566+ if info.Focused {
567+ return fmt.Sprintf("%s ", t.YoloDotsFocused)
568+ }
569+ return fmt.Sprintf("%s ", t.YoloDotsBlurred)
570+}
571+
572+func New(app *app.App) Editor {
573+ t := styles.CurrentTheme()
574+ ta := textarea.New()
575+ ta.SetStyles(t.S().TextArea)
546 ta.ShowLineNumbers = false
576 ta.ShowLineNumbers = false
547 ta.CharLimit = -1
577 ta.CharLimit = -1
548 ta.SetVirtualCursor(false)
578 ta.SetVirtualCursor(false)
549 ta.Focus()
579 ta.Focus()
550−
551 e := &editorCmp{
580 e := &editorCmp{
552 // TODO: remove the app instance from here
581 // TODO: remove the app instance from here
553 app: app,
582 app: app,
554 textarea: ta,
583 textarea: ta,
555 keyMap: DefaultEditorKeyMap(),
584 keyMap: DefaultEditorKeyMap(),
556 }
585 }
586+ e.setEditorPrompt()
557
587
558 e.randomizePlaceholders()
588 e.randomizePlaceholders()
559 e.textarea.Placeholder = e.readyPlaceholder
589 e.textarea.Placeholder = e.readyPlaceholder
internal/tui/components/dialogs/commands/commands.go+9
@@ -69,6 +69,7 @@ type (
69 ToggleCompactModeMsg struct{}
69 ToggleCompactModeMsg struct{}
70 ToggleThinkingMsg struct{}
70 ToggleThinkingMsg struct{}
71 OpenExternalEditorMsg struct{}
71 OpenExternalEditorMsg struct{}
72+ ToggleYoloModeMsg struct{}
72 CompactMsg struct {
73 CompactMsg struct {
73 SessionID string
74 SessionID string
74 }
75 }
@@ -362,6 +363,14 @@ func (c *commandDialogCmp) defaultCommands() []Command {
362 }
363 }
363
364
364 return append(commands, []Command{
365 return append(commands, []Command{
366+ {
367+ ID: "toggle_yolo",
368+ Title: "Toggle Yolo Mode",
369+ Description: "Toggle yolo mode",
370+ Handler: func(cmd Command) tea.Cmd {
371+ return util.CmdHandler(ToggleYoloModeMsg{})
372+ },
373+ },
365 {
374 {
366 ID: "toggle_help",
375 ID: "toggle_help",
367 Title: "Toggle Help",
376 Title: "Toggle Help",
internal/tui/page/chat/chat.go+5−1
@@ -300,7 +300,11 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
300 }
300 }
301
301
302 return p, tea.Batch(cmds...)
302 return p, tea.Batch(cmds...)
303−
303+ case commands.ToggleYoloModeMsg:
304+ // update the editor style
305+ u, cmd := p.editor.Update(msg)
306+ p.editor = u.(editor.Editor)
307+ return p, cmd
304 case pubsub.Event[history.File], sidebar.SessionFilesMsg:
308 case pubsub.Event[history.File], sidebar.SessionFilesMsg:
305 u, cmd := p.sidebar.Update(msg)
309 u, cmd := p.sidebar.Update(msg)
306 p.sidebar = u.(sidebar.Sidebar)
310 p.sidebar = u.(sidebar.Sidebar)
internal/tui/styles/charmtone.go+6
@@ -45,6 +45,7 @@ func NewCharmtoneTheme() *Theme {
45 Blue: charmtone.Malibu,
45 Blue: charmtone.Malibu,
46
46
47 Yellow: charmtone.Mustard,
47 Yellow: charmtone.Mustard,
48+ Citron: charmtone.Citron,
48
49
49 Green: charmtone.Julep,
50 Green: charmtone.Julep,
50 GreenDark: charmtone.Guac,
51 GreenDark: charmtone.Guac,
@@ -65,5 +66,10 @@ func NewCharmtoneTheme() *Theme {
65 t.ItemErrorIcon = t.ItemOfflineIcon.Foreground(charmtone.Coral)
66 t.ItemErrorIcon = t.ItemOfflineIcon.Foreground(charmtone.Coral)
66 t.ItemOnlineIcon = t.ItemOfflineIcon.Foreground(charmtone.Guac)
67 t.ItemOnlineIcon = t.ItemOfflineIcon.Foreground(charmtone.Guac)
67
68
69+ t.YoloIconFocused = lipgloss.NewStyle().Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
70+ t.YoloIconBlurred = t.YoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
71+ t.YoloDotsFocused = lipgloss.NewStyle().Foreground(charmtone.Zest).SetString(":::")
72+ t.YoloDotsBlurred = t.YoloDotsFocused.Foreground(charmtone.Squid)
73+
68 return t
74 return t
69}
75}
internal/tui/styles/theme.go+7
@@ -62,6 +62,7 @@ type Theme struct {
62
62
63 // Yellows
63 // Yellows
64 Yellow color.Color
64 Yellow color.Color
65+ Citron color.Color
65
66
66 // Greens
67 // Greens
67 Green color.Color
68 Green color.Color
@@ -83,6 +84,12 @@ type Theme struct {
83 ItemErrorIcon lipgloss.Style
84 ItemErrorIcon lipgloss.Style
84 ItemOnlineIcon lipgloss.Style
85 ItemOnlineIcon lipgloss.Style
85
86
87+ // Editor: Yolo Mode
88+ YoloIconFocused lipgloss.Style
89+ YoloIconBlurred lipgloss.Style
90+ YoloDotsFocused lipgloss.Style
91+ YoloDotsBlurred lipgloss.Style
92+
86 styles *Styles
93 styles *Styles
87}
94}
88
95
internal/tui/tui.go+2
@@ -174,6 +174,8 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
174 return a, util.CmdHandler(dialogs.OpenDialogMsg{
174 return a, util.CmdHandler(dialogs.OpenDialogMsg{
175 Model: quit.NewQuitDialog(),
175 Model: quit.NewQuitDialog(),
176 })
176 })
177+ case commands.ToggleYoloModeMsg:
178+ a.app.Permissions.SetSkipRequests(!a.app.Permissions.SkipRequests())
177 case commands.ToggleHelpMsg:
179 case commands.ToggleHelpMsg:
178 a.status.ToggleFullHelp()
180 a.status.ToggleFullHelp()
179 a.showingFullHelp = !a.showingFullHelp
181 a.showingFullHelp = !a.showingFullHelp