@@ -575,8 +575,11 @@ type setupOAuthDeviceMsg struct {
575575 err error
576576}
577577
578- func setupDevicePrepareCmd (name string ) tea.Cmd {
578+ func setupDevicePrepareCmd (name string , configPath ... string ) tea.Cmd {
579579 return func () tea.Msg {
580+ if err := preflightOAuthUserConfig (firstString (configPath )); err != nil {
581+ return setupOAuthDeviceMsg {providerID : name , err : err }
582+ }
580583 auth , cfg , err := oauthDevicePrepare (name )
581584 if err != nil {
582585 return setupOAuthDeviceMsg {providerID : name , err : err }
@@ -612,7 +615,7 @@ func (m model) startSetupDeviceLogin(descriptor providercatalog.Descriptor) (tea
612615 m .setup .oauthErr = ""
613616 m .setup .deviceUserCode = ""
614617 m .setup .deviceVerificationURI = ""
615- return m , setupDevicePrepareCmd (descriptor .ID )
618+ return m , setupDevicePrepareCmd (descriptor .ID , m . setup . configPath )
616619}
617620
618621// applySetupOAuthDeviceCode handles phase 1 of device-code login: show the code,
@@ -660,9 +663,12 @@ func (m model) applySetupOAuth(msg setupOAuthMsg) (tea.Model, tea.Cmd) {
660663 if msg .tokenLogin {
661664 // Early persist on the Update goroutine (see persistOAuthLoginProvider's
662665 // threading contract) so quitting setup after the login doesn't lose it;
663- // completeSetup persists the full profile with the chosen model anyway,
664- // so a failure here is recoverable and not fatal to setup.
665- _ = persistOAuthLoginProvider (m .setup .configPath , msg .providerID )
666+ // do not advance when that write fails or the stored token would have no
667+ // reachable provider profile after setup exits.
668+ if err := persistOAuthLoginProvider (m .setup .configPath , msg .providerID ); err != nil {
669+ m .setup .oauthErr = "Signed in, but the provider profile could not be saved: " + redaction .ErrorMessage (err , redaction.Options {})
670+ return m , nil
671+ }
666672 }
667673 m .setup .oauthErr = ""
668674 m .setup .err = ""
@@ -882,6 +888,9 @@ func (m model) completeSetup() (tea.Model, tea.Cmd) {
882888 })
883889 if err != nil {
884890 m .setup .err = err .Error ()
891+ if m .setup .oauthMode && m .setupProviderDescriptor ().OAuthMintsKey && strings .TrimSpace (apiKey ) != "" {
892+ m .setup .err = oauthMintedKeySaveError (m .setup .err , apiKey )
893+ }
885894 return m , nil
886895 }
887896
@@ -911,6 +920,10 @@ func (m model) completeSetup() (tea.Model, tea.Cmd) {
911920 return m .exitSetupToChat ()
912921}
913922
923+ func oauthMintedKeySaveError (message , apiKey string ) string {
924+ return fmt .Sprintf ("%s\n The minted API key was not saved. Copy it now before leaving Zero:\n %s" , message , apiKey )
925+ }
926+
914927func (m * model ) resetSetupModels () {
915928 option := m .setupProvider ()
916929 provider := setupProviderDescriptor (option )
0 commit comments