Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/root/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ func (f *newFlags) runNewCommand(cmd *cobra.Command, args []string) error {

sess := session.New(sessOpts...)

return runTUI(ctx, rt, sess, nil, nil, appOpts...)
return runTUI(ctx, rt, sess, nil, nil, nil, appOpts...)
}

func runTUI(ctx context.Context, rt runtime.Runtime, sess *session.Session, spawner tui.SessionSpawner, cleanup func(), opts ...app.Opt) error {
func runTUI(ctx context.Context, rt runtime.Runtime, sess *session.Session, spawner tui.SessionSpawner, cleanup func(), tuiOpts []tui.Option, opts ...app.Opt) error {
if gen := rt.TitleGenerator(); gen != nil {
opts = append(opts, app.WithTitleGenerator(gen))
}
Expand All @@ -106,7 +106,7 @@ func runTUI(ctx context.Context, rt runtime.Runtime, sess *session.Session, spaw
cleanup = func() {}
}
wd, _ := os.Getwd()
model := tui.New(ctx, spawner, a, wd, cleanup)
model := tui.New(ctx, spawner, a, wd, cleanup, tuiOpts...)

p := tea.NewProgram(model, tea.WithContext(ctx), tea.WithFilter(filter))
coalescer.SetSender(p.Send)
Expand Down
15 changes: 13 additions & 2 deletions cmd/root/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type runExecFlags struct {

// Run only
hideToolResults bool
lean bool

// globalPermissions holds the user-level global permission checker built
// from user config settings. Nil when no global permissions are configured.
Expand Down Expand Up @@ -117,6 +118,7 @@ func addRunOrExecFlags(cmd *cobra.Command, flags *runExecFlags) {
_ = cmd.PersistentFlags().MarkHidden("memprofile")
cmd.PersistentFlags().BoolVar(&flags.forceTUI, "force-tui", false, "Force TUI mode even when not in a terminal")
_ = cmd.PersistentFlags().MarkHidden("force-tui")
cmd.PersistentFlags().BoolVar(&flags.lean, "lean", false, "Use a simplified TUI with minimal chrome")
cmd.PersistentFlags().BoolVar(&flags.sandbox, "sandbox", false, "Run the agent inside a Docker sandbox (requires Docker Desktop with sandbox support)")
cmd.PersistentFlags().StringVar(&flags.sandboxTemplate, "template", "", "Template image for the sandbox (passed to docker sandbox create -t)")
cmd.MarkFlagsMutuallyExclusive("fake", "record")
Expand Down Expand Up @@ -275,7 +277,7 @@ func (f *runExecFlags) runOrExec(ctx context.Context, out *cli.Printer, args []s
}

sessStore := rt.SessionStore()
return runTUI(ctx, rt, sess, f.createSessionSpawner(agentSource, sessStore), initialTeamCleanup, opts...)
return runTUI(ctx, rt, sess, f.createSessionSpawner(agentSource, sessStore), initialTeamCleanup, f.tuiOpts(), opts...)
}

func (f *runExecFlags) loadAgentFrom(ctx context.Context, agentSource config.Source) (*teamloader.LoadResult, error) {
Expand Down Expand Up @@ -454,7 +456,16 @@ func (f *runExecFlags) launchTUI(ctx context.Context, out *cli.Printer, rt runti
return err
}

return runTUI(ctx, rt, sess, nil, nil, opts...)
return runTUI(ctx, rt, sess, nil, nil, f.tuiOpts(), opts...)
}

// tuiOpts returns the TUI options derived from the current flags.
func (f *runExecFlags) tuiOpts() []tui.Option {
var opts []tui.Option
if f.lean {
opts = append(opts, tui.WithLeanMode())
}
return opts
}

func (f *runExecFlags) buildAppOpts(args []string) ([]app.Opt, error) {
Expand Down
58 changes: 45 additions & 13 deletions pkg/tui/page/chat/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ type chatPage struct {
sessionState *service.SessionState

// State
working bool
working bool
leanMode bool

msgCancel context.CancelFunc
streamCancelled bool
Expand Down Expand Up @@ -174,6 +175,16 @@ type chatPage struct {
func (p *chatPage) computeSidebarLayout() sidebarLayout {
innerWidth := p.width - appPaddingHorizontal

// Lean mode: no sidebar at all
if p.leanMode {
return sidebarLayout{
mode: sidebarCollapsedNarrow,
innerWidth: innerWidth,
chatWidth: innerWidth,
chatHeight: max(1, p.height),
}
}

var mode sidebarLayoutMode
switch {
case p.width >= minWindowWidth && !p.sidebar.IsCollapsed():
Expand Down Expand Up @@ -300,7 +311,7 @@ func getEditorDisplayNameFromEnv(visual, editorEnv string) string {
}

// New creates a new chat page
func New(a *app.App, sessionState *service.SessionState) Page {
func New(a *app.App, sessionState *service.SessionState, opts ...PageOption) Page {
p := &chatPage{
sidebar: sidebar.New(sessionState),
messages: messages.New(sessionState),
Expand All @@ -309,9 +320,23 @@ func New(a *app.App, sessionState *service.SessionState) Page {
sessionState: sessionState,
}

for _, opt := range opts {
opt(p)
}

return p
}

// PageOption configures a chat page.
type PageOption func(*chatPage)

// WithLeanMode creates a lean chat page with no sidebar.
func WithLeanMode() PageOption {
return func(p *chatPage) {
p.leanMode = true
}
}

// Init initializes the chat page
func (p *chatPage) Init() tea.Cmd {
var cmds []tea.Cmd
Expand Down Expand Up @@ -518,19 +543,26 @@ func (p *chatPage) View() string {
bodyContent = lipgloss.JoinHorizontal(lipgloss.Left, chatView, toggleCol, sidebarView)

case sidebarCollapsed, sidebarCollapsedNarrow:
sidebarRendered := p.renderCollapsedSidebar(sl)

chatView := styles.ChatStyle.
Height(sl.chatHeight).
Width(sl.innerWidth).
Render(messagesView)

bodyContent = lipgloss.JoinVertical(lipgloss.Top, sidebarRendered, chatView)
if p.leanMode {
// Lean mode: no sidebar header, no fixed height
bodyContent = styles.ChatStyle.
Width(sl.innerWidth).
Render(messagesView)
} else {
sidebarRendered := p.renderCollapsedSidebar(sl)
chatView := styles.ChatStyle.
Height(sl.chatHeight).
Width(sl.innerWidth).
Render(messagesView)
bodyContent = lipgloss.JoinVertical(lipgloss.Top, sidebarRendered, chatView)
}
}

return styles.AppStyle.
Height(p.height).
Render(bodyContent)
appStyle := styles.AppStyle
if !p.leanMode {
appStyle = appStyle.Height(p.height)
}
return appStyle.Render(bodyContent)
}

// renderSidebarHandle renders the sidebar toggle/resize handle.
Expand Down
Loading
Loading