@@ -8,41 +8,50 @@ import (
88)
99
1010// ──────────────────────────────────────────────────────────────
11- // Root model — routes between boot and chat screens
11+ // Root model — routes between setup, boot, and chat screens
1212// ──────────────────────────────────────────────────────────────
1313
1414type screen int
1515
1616const (
17- screenBoot screen = iota
17+ screenBoot screen = iota
1818 screenChat
19+ screenSetup
1920)
2021
2122type appModel struct {
2223 screen screen
2324 boot bootModel
2425 chat chatModel
26+ setup setupModel
2527 config * Config
2628}
2729
2830func newAppModel (cfg * Config ) appModel {
2931 startScreen := screenBoot
30- if os .Getenv ("CODEBASE_NOBOOT" ) != "" {
32+ if cfg .NeedsSetup {
33+ startScreen = screenSetup
34+ } else if os .Getenv ("CODEBASE_NOBOOT" ) != "" {
3135 startScreen = screenChat
3236 }
3337 return appModel {
3438 screen : startScreen ,
3539 boot : newBootModel (cfg ),
3640 chat : newChatModel (cfg ),
41+ setup : newSetupModel (),
3742 config : cfg ,
3843 }
3944}
4045
4146func (m appModel ) Init () tea.Cmd {
42- if m .screen == screenChat {
47+ switch m .screen {
48+ case screenSetup :
49+ return m .setup .Init ()
50+ case screenChat :
4351 return m .chat .Init ()
52+ default :
53+ return m .boot .Init ()
4454 }
45- return m .boot .Init ()
4655}
4756
4857func (m appModel ) Update (msg tea.Msg ) (tea.Model , tea.Cmd ) {
@@ -54,13 +63,58 @@ func (m appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5463 }
5564 }
5665
57- // Window size goes to both screens
66+ // Window size goes to all screens
5867 if wsMsg , ok := msg .(tea.WindowSizeMsg ); ok {
5968 m .boot .width = wsMsg .Width
6069 m .boot .height = wsMsg .Height
6170 }
6271
6372 switch m .screen {
73+ case screenSetup :
74+ switch msg := msg .(type ) {
75+ case setupDoneMsg :
76+ // Save config
77+ if err := saveSavedConfig (msg .config ); err != nil {
78+ // Continue anyway — config is in memory
79+ _ = err
80+ }
81+ // Apply to runtime config
82+ m .config .APIKey = msg .config .APIKey
83+ m .config .BaseURL = msg .config .BaseURL
84+ m .config .Model = msg .config .Model
85+ m .config .NeedsSetup = false
86+
87+ // Set glue env vars
88+ if msg .config .GlueAPIKey != "" {
89+ os .Setenv ("GLUE_API_KEY" , msg .config .GlueAPIKey )
90+ }
91+ if msg .config .GlueBaseURL != "" {
92+ os .Setenv ("GLUE_BASE_URL" , msg .config .GlueBaseURL )
93+ }
94+ if msg .config .GlueFastModel != "" {
95+ os .Setenv ("GLUE_FAST_MODEL" , msg .config .GlueFastModel )
96+ }
97+ if msg .config .GlueSmartModel != "" {
98+ os .Setenv ("GLUE_SMART_MODEL" , msg .config .GlueSmartModel )
99+ }
100+
101+ // Recreate boot and chat models with updated config
102+ m .boot = newBootModel (m .config )
103+ m .chat = newChatModel (m .config )
104+
105+ // Transition to boot screen
106+ if os .Getenv ("CODEBASE_NOBOOT" ) != "" {
107+ m .screen = screenChat
108+ return m , m .chat .Init ()
109+ }
110+ m .screen = screenBoot
111+ return m , m .boot .Init ()
112+ default :
113+ var cmd tea.Cmd
114+ m .setup , cmd = m .setup .Update (msg )
115+ return m , cmd
116+ }
117+
64118 case screenBoot :
65119 switch msg .(type ) {
66120 case bootDoneMsg :
@@ -78,6 +132,13 @@ func (m appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
78132 return m , cmd
79133
80134 case screenChat :
135+ // Check for setup command trigger
136+ if setupMsg , ok := msg .(enterSetupMsg ); ok {
137+ _ = setupMsg
138+ m .setup = newSetupModel ()
139+ m .screen = screenSetup
140+ return m , m .setup .Init ()
141+ }
81142 var cmd tea.Cmd
82143 m .chat , cmd = m .chat .Update (msg )
83144 return m , cmd
@@ -88,6 +149,8 @@ func (m appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
88149
89150func (m appModel ) View () string {
90151 switch m .screen {
152+ case screenSetup :
153+ return m .setup .View ()
91154 case screenBoot :
92155 return m .boot .View ()
93156 case screenChat :
@@ -96,6 +159,9 @@ func (m appModel) View() string {
96159 return ""
97160}
98161
162+ // enterSetupMsg triggers the setup wizard from a /setup command.
163+ type enterSetupMsg struct {}
164+
99165// Cleanup gracefully shuts down background goroutines and processes.
100166// Called from main.go's defer chain before terminal restoration.
101167func (m * appModel ) Cleanup () {
0 commit comments