66 "fmt"
77 "os"
88 "os/exec"
9+ "os/signal"
910 "path/filepath"
1011 "runtime"
1112 "strings"
@@ -67,42 +68,49 @@ func Launch(modelFlag string, configOnly bool, hubURL string) error {
6768 fmt .Printf (" ✓ API key: ...%s\n " , suffix )
6869 }
6970
70- // Step 3: Model selection
71- selectedModel := modelFlag
72- if selectedModel == "" {
73- models , err := api .ListModels (cfg .BaseURL , cfg .APIKey )
74- if err != nil {
75- return fmt .Errorf ("failed to list models: %w" , err )
76- }
77- if len (models ) == 0 {
78- return fmt .Errorf ("no models available" )
79- }
71+ // Step 3: Check if already configured
72+ alreadyConfigured := isHPPConfigured ()
8073
81- // Filter text models (exclude image models)
82- var textModels []api.Model
83- for _ , m := range models {
84- if ! strings .Contains (m .ID , "dall-e" ) && ! strings .Contains (m .ID , "image" ) {
85- textModels = append (textModels , m )
74+ if alreadyConfigured && modelFlag == "" {
75+ // Already set up, no model change requested
76+ currentModel := getCurrentModel ()
77+ fmt .Printf (" ✓ HPP already configured (model: %s)\n " , currentModel )
78+ } else {
79+ // Need to configure or reconfigure
80+ selectedModel := modelFlag
81+ if selectedModel == "" {
82+ models , err := api .ListModels (cfg .BaseURL , cfg .APIKey )
83+ if err != nil {
84+ return fmt .Errorf ("failed to list models: %w" , err )
85+ }
86+ if len (models ) == 0 {
87+ return fmt .Errorf ("no models available" )
8688 }
87- }
8889
89- selectedModel = selectModel (textModels )
90- if selectedModel == "" {
91- return fmt .Errorf ("no model selected" )
90+ // Filter text models (exclude image models)
91+ var textModels []api.Model
92+ for _ , m := range models {
93+ if ! strings .Contains (m .ID , "dall-e" ) && ! strings .Contains (m .ID , "image" ) {
94+ textModels = append (textModels , m )
95+ }
96+ }
97+
98+ selectedModel = selectModel (textModels )
99+ if selectedModel == "" {
100+ return fmt .Errorf ("no model selected" )
101+ }
92102 }
93- }
94- fmt .Printf (" ✓ Model: %s\n " , selectedModel )
103+ fmt .Printf (" ✓ Model: %s\n " , selectedModel )
95104
96- // Step 4: Configure OpenClaw
97- fmt .Println (" Configuring OpenClaw..." )
98- if err := configureOpenClaw (cfg , selectedModel ); err != nil {
99- return fmt .Errorf ("failed to configure: %w" , err )
100- }
101- fmt .Println (" ✓ HPP provider configured in OpenClaw" )
105+ fmt .Println (" Configuring OpenClaw..." )
106+ if err := configureOpenClaw (cfg , selectedModel ); err != nil {
107+ return fmt .Errorf ("failed to configure: %w" , err )
108+ }
109+ fmt .Println (" ✓ HPP provider configured in OpenClaw" )
102110
103- // Validate config
104- if err := validateOpenClawConfig (); err != nil {
105- fmt . Printf ( " ⚠ Config validation: %s \n " , err )
111+ if err := validateOpenClawConfig (); err != nil {
112+ fmt . Printf ( " ⚠ Config validation: %s \n " , err )
113+ }
106114 }
107115
108116 if configOnly {
@@ -112,24 +120,40 @@ func Launch(modelFlag string, configOnly bool, hubURL string) error {
112120 }
113121
114122 // Step 5: Ask about Telegram setup (before starting gateway)
115- if ! isTelegramConfigured () {
123+ telegramWasConfigured := isTelegramConfigured ()
124+ if ! telegramWasConfigured {
116125 fmt .Println ()
117126 if promptYesNo (" Set up Telegram bot?" ) {
118127 SetupTelegram ()
119128 }
120129 }
130+ telegramChanged := ! telegramWasConfigured && isTelegramConfigured ()
121131
122- // Step 6: Start OpenClaw
123- fmt .Println (" Starting OpenClaw gateway..." )
124- if err := startOpenClaw (); err != nil {
125- fmt .Printf (" ⚠ Failed to start gateway: %s\n " , err )
126- if runtime .GOOS == "windows" {
127- fmt .Println (" Start manually in a new terminal: openclaw gateway" )
132+ // Step 6: Start or restart Gateway
133+ if isGatewayRunning () {
134+ if telegramChanged {
135+ fmt .Println (" Restarting gateway to apply Telegram settings..." )
136+ if runtime .GOOS == "windows" {
137+ fmt .Println (" ⚠ Please restart the gateway manually (Ctrl+C in gateway terminal, then run 'openclaw gateway' again)" )
138+ } else {
139+ _ = RunCommand ("gateway" , "restart" )
140+ fmt .Println (" ✓ Gateway restarted" )
141+ }
128142 } else {
129- fmt .Println (" Start manually: openclaw gateway start " )
143+ fmt .Println (" ✓ Gateway already running " )
130144 }
131145 } else {
132- fmt .Println (" ✓ OpenClaw gateway running" )
146+ fmt .Println (" Starting OpenClaw gateway..." )
147+ if err := startOpenClaw (); err != nil {
148+ fmt .Printf (" ⚠ Failed to start gateway: %s\n " , err )
149+ if runtime .GOOS == "windows" {
150+ fmt .Println (" Start manually in a new terminal: openclaw gateway" )
151+ } else {
152+ fmt .Println (" Start manually: openclaw gateway start" )
153+ }
154+ } else {
155+ fmt .Println (" ✓ OpenClaw gateway running" )
156+ }
133157 }
134158
135159 fmt .Println ()
@@ -368,12 +392,37 @@ func validateOpenClawConfig() error {
368392func startOpenClaw () error {
369393 if runtime .GOOS == "windows" {
370394 // Windows: run gateway in foreground (daemon not supported)
395+ // Ensure child process is killed on Ctrl+C
371396 fmt .Println (" Starting gateway in foreground (press Ctrl+C to stop)..." )
372397 cmd := exec .Command ("openclaw" , "gateway" )
373398 cmd .Stdin = os .Stdin
374399 cmd .Stdout = os .Stdout
375400 cmd .Stderr = os .Stderr
376- return cmd .Run ()
401+
402+ if err := cmd .Start (); err != nil {
403+ return err
404+ }
405+
406+ // Handle Ctrl+C — kill child process
407+ sigChan := make (chan os.Signal , 1 )
408+ signal .Notify (sigChan , os .Interrupt )
409+
410+ done := make (chan error , 1 )
411+ go func () {
412+ done <- cmd .Wait ()
413+ }()
414+
415+ select {
416+ case <- sigChan :
417+ // Ctrl+C received — kill child process
418+ if cmd .Process != nil {
419+ cmd .Process .Kill ()
420+ }
421+ fmt .Println ("\n Gateway stopped." )
422+ return nil
423+ case err := <- done :
424+ return err
425+ }
377426 }
378427 // macOS/Linux: start as daemon
379428 cmd := exec .Command ("openclaw" , "gateway" , "start" )
@@ -395,6 +444,52 @@ func isWSL() bool {
395444 return strings .Contains (lower , "microsoft" ) || strings .Contains (lower , "wsl" )
396445}
397446
447+ // isHPPConfigured checks if HPP provider is already set up in OpenClaw config
448+ func isHPPConfigured () bool {
449+ home , _ := os .UserHomeDir ()
450+ configPath := filepath .Join (home , ".openclaw" , "openclaw.json" )
451+ data , err := os .ReadFile (configPath )
452+ if err != nil {
453+ return false
454+ }
455+ var cfg map [string ]interface {}
456+ if json .Unmarshal (data , & cfg ) != nil {
457+ return false
458+ }
459+ models , _ := cfg ["models" ].(map [string ]interface {})
460+ providers , _ := models ["providers" ].(map [string ]interface {})
461+ hpp , _ := providers ["hpp" ].(map [string ]interface {})
462+ return hpp ["apiKey" ] != nil
463+ }
464+
465+ // getCurrentModel returns the current default model from OpenClaw config
466+ func getCurrentModel () string {
467+ home , _ := os .UserHomeDir ()
468+ configPath := filepath .Join (home , ".openclaw" , "openclaw.json" )
469+ data , err := os .ReadFile (configPath )
470+ if err != nil {
471+ return "unknown"
472+ }
473+ var cfg map [string ]interface {}
474+ if json .Unmarshal (data , & cfg ) != nil {
475+ return "unknown"
476+ }
477+ agents , _ := cfg ["agents" ].(map [string ]interface {})
478+ defaults , _ := agents ["defaults" ].(map [string ]interface {})
479+ model , _ := defaults ["model" ].(map [string ]interface {})
480+ primary , _ := model ["primary" ].(string )
481+ if primary == "" {
482+ return "unknown"
483+ }
484+ return primary
485+ }
486+
487+ // isGatewayRunning checks if OpenClaw gateway is already running
488+ func isGatewayRunning () bool {
489+ cmd := exec .Command ("openclaw" , "health" )
490+ return cmd .Run () == nil
491+ }
492+
398493// isTelegramConfigured checks if Telegram is already set up in OpenClaw config
399494func isTelegramConfigured () bool {
400495 home , _ := os .UserHomeDir ()
0 commit comments