@@ -258,8 +258,6 @@ func New(com *common.Common) *UI {
258258 com: com,
259259 dialog: dialog.NewOverlay(),
260260 keyMap: keyMap,
261− focus: uiFocusNone,
262− state: uiOnboarding,
263261 textarea: ta,
264262 chat: ch,
265263 completions: comp,
@@ -271,18 +269,6 @@ func New(com *common.Common) *UI {
271269
272270 status := NewStatus(com, ui)
273271
274− // set onboarding state defaults
275− ui.onboarding.yesInitializeSelected = true
276−
277− if !com.Config().IsConfigured() {
278− ui.state = uiOnboarding
279− } else if n, _ := config.ProjectNeedsInitialization(); n {
280− ui.state = uiInitialize
281− } else {
282− ui.state = uiLanding
283− ui.focus = uiFocusEditor
284− }
285−
286272 ui.setEditorPrompt(false)
287273 ui.randomizePlaceholders()
288274 ui.textarea.Placeholder = ui.readyPlaceholder
@@ -291,6 +277,20 @@ func New(com *common.Common) *UI {
291277 // Initialize compact mode from config
292278 ui.forceCompactMode = com.Config().Options.TUI.CompactMode
293279
280+ // set onboarding state defaults
281+ ui.onboarding.yesInitializeSelected = true
282+
283+ desiredState := uiLanding
284+ desiredFocus := uiFocusEditor
285+ if !com.Config().IsConfigured() {
286+ desiredState = uiOnboarding
287+ } else if n, _ := config.ProjectNeedsInitialization(); n {
288+ desiredState = uiInitialize
289+ }
290+
291+ // set initial state
292+ ui.setState(desiredState, desiredFocus)
293+
294294 return ui
295295}
296296
@@ -310,6 +310,14 @@ func (m *UI) Init() tea.Cmd {
310310 return tea.Batch(cmds...)
311311}
312312
313+// setState changes the UI state and focus.
314+func (m *UI) setState(state uiState, focus uiFocusState) {
315+ m.state = state
316+ m.focus = focus
317+ // Changing the state may change layout, so update it.
318+ m.updateLayoutAndSize()
319+}
320+
313321// loadCustomCommands loads the custom commands asynchronously.
314322func (m *UI) loadCustomCommands() tea.Cmd {
315323 return func() tea.Msg {
@@ -360,10 +368,10 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
360368 cmds = append(cmds, timage.RequestCapabilities(m.imgCaps.Env))
361369 }
362370 case loadSessionMsg:
363− m.state = uiChat
364371 if m.forceCompactMode {
365372 m.isCompact = true
366373 }
374+ m.setState(uiChat, m.focus)
367375 m.session = msg.session
368376 m.sessionFiles = msg.files
369377 msgs, err := m.com.App.Messages.List(context.Background(), m.session.ID)
@@ -493,7 +501,6 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
493501 return m, nil
494502 case tea.WindowSizeMsg:
495503 m.width, m.height = msg.Width, msg.Height
496− m.handleCompactMode(m.width, m.height)
497504 m.updateLayoutAndSize()
498505 // XXX: We need to store cell dimensions for image rendering.
499506 m.imgCaps.Columns, m.imgCaps.Rows = msg.Width, msg.Height
@@ -1212,9 +1219,7 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
12121219 m.dialog.CloseDialog(dialog.ModelsID)
12131220
12141221 if isOnboarding {
1215− m.state = uiLanding
1216− m.focus = uiFocusEditor
1217−
1222+ m.setState(uiLanding, uiFocusEditor)
12181223 m.com.Config().SetupAgents()
12191224 if err := m.com.App.InitCoderAgent(context.TODO()); err != nil {
12201225 cmds = append(cmds, uiutil.ReportError(err))
@@ -1507,7 +1512,7 @@ func (m *UI) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd {
15071512 m.newSession()
15081513 case key.Matches(msg, m.keyMap.Tab):
15091514 if m.state != uiLanding {
1510− m.focus = uiFocusMain
1515+ m.setState(m.state, uiFocusMain)
15111516 m.textarea.Blur()
15121517 m.chat.Focus()
15131518 m.chat.SetSelected(m.chat.Len() - 1)
@@ -2054,29 +2059,26 @@ func (m *UI) toggleCompactMode() tea.Cmd {
20542059 return uiutil.ReportError(err)
20552060 }
20562061
2057− m.handleCompactMode(m.width, m.height)
20582062 m.updateLayoutAndSize()
20592063
20602064 return nil
20612065}
20622066
2063−// handleCompactMode updates the UI state based on window size and compact mode setting.
2064−func (m *UI) handleCompactMode(newWidth, newHeight int) {
2067+// updateLayoutAndSize updates the layout and sizes of UI components.
2068+func (m *UI) updateLayoutAndSize() {
2069+ // Determine if we should be in compact mode
20652070 if m.state == uiChat {
20662071 if m.forceCompactMode {
20672072 m.isCompact = true
20682073 return
20692074 }
2070− if newWidth < compactModeWidthBreakpoint || newHeight < compactModeHeightBreakpoint {
2075+ if m.width < compactModeWidthBreakpoint || m.height < compactModeHeightBreakpoint {
20712076 m.isCompact = true
20722077 } else {
20732078 m.isCompact = false
20742079 }
20752080 }
2076−}
20772081
2078−// updateLayoutAndSize updates the layout and sizes of UI components.
2079−func (m *UI) updateLayoutAndSize() {
20802082 m.layout = m.generateLayout(m.width, m.height)
20812083 m.updateSize()
20822084}
@@ -2121,7 +2123,7 @@ func (m *UI) generateLayout(w, h int) layout {
21212123 const landingHeaderHeight = 4
21222124
21232125 var helpKeyMap help.KeyMap = m
2124− if m.status.ShowingAll() {
2126+ if m.status != nil && m.status.ShowingAll() {
21252127 for _, row := range helpKeyMap.FullHelp() {
21262128 helpHeight = max(helpHeight, len(row))
21272129 }
@@ -2527,7 +2529,6 @@ func (m *UI) sendMessage(content string, attachments ...message.Attachment) tea.
25272529 if err != nil {
25282530 return uiutil.ReportError(err)
25292531 }
2530− m.state = uiChat
25312532 if m.forceCompactMode {
25322533 m.isCompact = true
25332534 }
@@ -2535,6 +2536,7 @@ func (m *UI) sendMessage(content string, attachments ...message.Attachment) tea.
25352536 m.session = &newSession
25362537 cmds = append(cmds, m.loadSession(newSession.ID))
25372538 }
2539+ m.setState(uiChat, m.focus)
25382540 }
25392541
25402542 // Capture session ID to avoid race with main goroutine updating m.session.
@@ -2782,8 +2784,7 @@ func (m *UI) newSession() {
27822784
27832785 m.session = nil
27842786 m.sessionFiles = nil
2785− m.state = uiLanding
2786− m.focus = uiFocusEditor
2787+ m.setState(uiLanding, uiFocusEditor)
27872788 m.textarea.Focus()
27882789 m.chat.Blur()
27892790 m.chat.ClearMessages()