@@ -2,15 +2,20 @@ package main
22
33import (
44 "fmt"
5+ "log"
56 "os"
7+ "os/signal"
68 "strings"
9+ "syscall"
710 "time"
811
912 "github.com/agnath18K/lumo/pkg/agent"
1013 "github.com/agnath18K/lumo/pkg/config"
14+ "github.com/agnath18K/lumo/pkg/daemon"
1115 "github.com/agnath18K/lumo/pkg/executor"
1216 "github.com/agnath18K/lumo/pkg/nlp"
1317 "github.com/agnath18K/lumo/pkg/pipe"
18+ "github.com/agnath18K/lumo/pkg/server"
1419 "github.com/agnath18K/lumo/pkg/terminal"
1520 "github.com/agnath18K/lumo/pkg/utils"
1621 "github.com/agnath18K/lumo/pkg/version"
@@ -32,6 +37,78 @@ func main() {
3237 // Initialize agent
3338 _ = agent .Initialize (cfg , exec )
3439
40+ // Check for server daemon commands
41+ if len (os .Args ) > 1 {
42+ // Handle server daemon commands
43+ if os .Args [1 ] == "server:start" {
44+ // Start the server daemon
45+ d := daemon .New (cfg )
46+ if err := d .Start (); err != nil {
47+ fmt .Fprintf (os .Stderr , "Error starting server daemon: %v\n " , err )
48+ os .Exit (1 )
49+ }
50+ fmt .Println ("Server daemon started" )
51+ os .Exit (0 )
52+ } else if os .Args [1 ] == "server:stop" {
53+ // Stop the server daemon
54+ d := daemon .New (cfg )
55+ if err := d .Stop (); err != nil {
56+ fmt .Fprintf (os .Stderr , "Error stopping server daemon: %v\n " , err )
57+ os .Exit (1 )
58+ }
59+ fmt .Println ("Server daemon stopped" )
60+ os .Exit (0 )
61+ } else if os .Args [1 ] == "server:status" {
62+ // Check server daemon status
63+ d := daemon .New (cfg )
64+ running , pid , err := d .Status ()
65+ if err != nil {
66+ fmt .Fprintf (os .Stderr , "Error checking server daemon status: %v\n " , err )
67+ os .Exit (1 )
68+ }
69+ if running {
70+ fmt .Printf ("Server daemon is running with PID %d\n " , pid )
71+ } else {
72+ fmt .Println ("Server daemon is not running" )
73+ }
74+ os .Exit (0 )
75+ } else if os .Args [1 ] == "server:daemon" {
76+ // This is the daemon process
77+ d := daemon .New (cfg )
78+ if err := d .RunServer (exec ); err != nil {
79+ fmt .Fprintf (os .Stderr , "Error running server daemon: %v\n " , err )
80+ os .Exit (1 )
81+ }
82+ os .Exit (0 )
83+ }
84+ }
85+
86+ // Check if a server daemon is already running
87+ d := daemon .New (cfg )
88+ running , _ , err := d .IsRunning ()
89+ if err != nil {
90+ fmt .Fprintf (os .Stderr , "Error checking if server daemon is running: %v\n " , err )
91+ }
92+
93+ // Start the REST server if enabled and not already running as a daemon
94+ var srv * server.Server
95+ if cfg .EnableServer && ! running {
96+ srv = server .New (cfg , exec )
97+ if err := srv .Start (); err != nil {
98+ fmt .Fprintf (os .Stderr , "Error starting REST server: %v\n " , err )
99+ // Continue execution even if server fails to start
100+ } else {
101+ // Set up signal handling for graceful shutdown
102+ setupSignalHandling (srv )
103+
104+ // Notify the user that the server is running
105+ if ! cfg .ServerQuietOutput {
106+ fmt .Fprintf (os .Stderr , "\n NOTE: Lumo REST server is running on port %d\n " , cfg .ServerPort )
107+ fmt .Fprintf (os .Stderr , "To disable the server, run: lumo config:server disable\n \n " )
108+ }
109+ }
110+ }
111+
35112 // Check if input is being piped
36113 stat , _ := os .Stdin .Stat ()
37114 isPiped := (stat .Mode () & os .ModeCharDevice ) == 0
@@ -80,7 +157,7 @@ func main() {
80157 hasPrefix := false
81158 for _ , prefix := range []string {"lumo:" , "shell:" , "ask:" , "ai:" , "auto:" , "agent:" ,
82159 "health:" , "syshealth:" , "report:" , "sysreport:" , "chat:" , "talk:" , "config:" ,
83- "speed:" , "speedtest:" , "speed-test:" , "magic:" , "clipboard" , "connect" , "create" } {
160+ "speed:" , "speedtest:" , "speed-test:" , "magic:" , "clipboard" , "connect" , "create" , "server:" } {
84161 if strings .HasPrefix (command , prefix ) {
85162 hasPrefix = true
86163 break
@@ -121,6 +198,43 @@ func main() {
121198 os .Exit (1 )
122199 }
123200 term .Display (result )
201+ } else if strings .HasPrefix (command , "server:" ) {
202+ // Handle server commands
203+ intent := strings .TrimSpace (command [7 :])
204+ if intent == "start" {
205+ // Start the server daemon
206+ d := daemon .New (cfg )
207+ if err := d .Start (); err != nil {
208+ fmt .Fprintf (os .Stderr , "Error starting server daemon: %v\n " , err )
209+ os .Exit (1 )
210+ }
211+ fmt .Println ("Server daemon started" )
212+ } else if intent == "stop" {
213+ // Stop the server daemon
214+ d := daemon .New (cfg )
215+ if err := d .Stop (); err != nil {
216+ fmt .Fprintf (os .Stderr , "Error stopping server daemon: %v\n " , err )
217+ os .Exit (1 )
218+ }
219+ fmt .Println ("Server daemon stopped" )
220+ } else if intent == "status" {
221+ // Check server daemon status
222+ d := daemon .New (cfg )
223+ running , pid , err := d .Status ()
224+ if err != nil {
225+ fmt .Fprintf (os .Stderr , "Error checking server daemon status: %v\n " , err )
226+ os .Exit (1 )
227+ }
228+ if running {
229+ fmt .Printf ("Server daemon is running with PID %d\n " , pid )
230+ } else {
231+ fmt .Println ("Server daemon is not running" )
232+ }
233+ } else {
234+ fmt .Fprintf (os .Stderr , "Unknown server command: %s\n " , intent )
235+ fmt .Println ("Available commands: server:start, server:stop, server:status" )
236+ os .Exit (1 )
237+ }
124238 } else if strings .HasPrefix (command , "lumo:" ) {
125239 // Legacy "lumo:" prefix is now treated as an AI query for safety
126240 intent := strings .TrimSpace (command [5 :])
@@ -136,144 +250,6 @@ func main() {
136250 os .Exit (1 )
137251 }
138252 term .Display (result )
139- } else if strings .HasPrefix (command , "health:" ) || strings .HasPrefix (command , "syshealth:" ) {
140- // Handle system health commands
141- var intent string
142- if strings .HasPrefix (command , "health:" ) {
143- intent = strings .TrimSpace (command [7 :])
144- } else {
145- intent = strings .TrimSpace (command [10 :])
146- }
147- cmd := & nlp.Command {
148- Type : nlp .CommandTypeSystemHealth ,
149- Intent : intent ,
150- Parameters : make (map [string ]string ),
151- RawInput : command ,
152- }
153- result , err := exec .Execute (cmd )
154- if err != nil {
155- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
156- os .Exit (1 )
157- }
158- term .Display (result )
159- } else if strings .HasPrefix (command , "report:" ) || strings .HasPrefix (command , "sysreport:" ) {
160- // Handle system report commands
161- var intent string
162- if strings .HasPrefix (command , "report:" ) {
163- intent = strings .TrimSpace (command [7 :])
164- } else {
165- intent = strings .TrimSpace (command [10 :])
166- }
167- cmd := & nlp.Command {
168- Type : nlp .CommandTypeSystemReport ,
169- Intent : intent ,
170- Parameters : make (map [string ]string ),
171- RawInput : command ,
172- }
173- result , err := exec .Execute (cmd )
174- if err != nil {
175- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
176- os .Exit (1 )
177- }
178- term .Display (result )
179- } else if strings .HasPrefix (command , "chat:" ) || strings .HasPrefix (command , "talk:" ) || command == "chat" || command == "talk" {
180- // Handle chat commands
181- var intent string
182- var rawInput string
183-
184- if command == "chat" || command == "talk" {
185- // Empty chat command to start REPL mode
186- intent = ""
187- rawInput = command + ":"
188- } else if strings .HasPrefix (command , "chat:" ) {
189- intent = strings .TrimSpace (command [5 :])
190- rawInput = command
191- } else {
192- intent = strings .TrimSpace (command [5 :])
193- rawInput = command
194- }
195-
196- cmd := & nlp.Command {
197- Type : nlp .CommandTypeChat ,
198- Intent : intent ,
199- Parameters : make (map [string ]string ),
200- RawInput : rawInput ,
201- }
202- result , err := exec .Execute (cmd )
203- if err != nil {
204- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
205- os .Exit (1 )
206- }
207- term .Display (result )
208- } else if strings .HasPrefix (command , "config:" ) {
209- // Handle configuration commands
210- intent := strings .TrimSpace (command [7 :])
211- cmd := & nlp.Command {
212- Type : nlp .CommandTypeConfig ,
213- Intent : intent ,
214- Parameters : make (map [string ]string ),
215- RawInput : command ,
216- }
217- result , err := exec .Execute (cmd )
218- if err != nil {
219- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
220- os .Exit (1 )
221- }
222- term .Display (result )
223- } else if strings .HasPrefix (command , "magic:" ) {
224- // Handle magic commands
225- intent := strings .TrimSpace (command [6 :])
226- cmd := & nlp.Command {
227- Type : nlp .CommandTypeMagic ,
228- Intent : intent ,
229- Parameters : make (map [string ]string ),
230- RawInput : command ,
231- }
232- result , err := exec .Execute (cmd )
233- if err != nil {
234- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
235- os .Exit (1 )
236- }
237- term .Display (result )
238- } else if command == "clipboard" || strings .HasPrefix (command , "clipboard " ) {
239- // Handle clipboard commands
240- intent := ""
241- if strings .HasPrefix (command , "clipboard " ) {
242- intent = strings .TrimSpace (command [10 :])
243- }
244- cmd := & nlp.Command {
245- Type : nlp .CommandTypeClipboard ,
246- Intent : intent ,
247- Parameters : make (map [string ]string ),
248- RawInput : command ,
249- }
250- result , err := exec .Execute (cmd )
251- if err != nil {
252- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
253- os .Exit (1 )
254- }
255- term .Display (result )
256- } else if strings .HasPrefix (command , "create:" ) || command == "create" {
257- // Handle create commands
258- var intent string
259- if strings .HasPrefix (command , "create:" ) {
260- intent = strings .TrimSpace (command [7 :])
261- } else {
262- // Just "create" shows help
263- intent = ""
264- }
265- cmd := & nlp.Command {
266- Type : nlp .CommandTypeCreate ,
267- Intent : intent ,
268- Parameters : make (map [string ]string ),
269- RawInput : command ,
270- }
271- result , err := exec .Execute (cmd )
272- if err != nil {
273- fmt .Fprintf (os .Stderr , "Error executing command: %v\n " , err )
274- os .Exit (1 )
275- }
276- term .Display (result )
277253 } else {
278254 processCommand (command , parser , exec , term )
279255 }
@@ -288,6 +264,27 @@ func main() {
288264 }
289265}
290266
267+ // setupSignalHandling sets up signal handling for graceful shutdown
268+ func setupSignalHandling (srv * server.Server ) {
269+ c := make (chan os.Signal , 1 )
270+ signal .Notify (c , os .Interrupt , syscall .SIGTERM )
271+
272+ go func () {
273+ <- c
274+ if ! srv .GetConfig ().ServerQuietOutput {
275+ log .Println ("Shutting down REST server..." )
276+ }
277+ if err := srv .Stop (); err != nil {
278+ if ! srv .GetConfig ().ServerQuietOutput {
279+ log .Printf ("Error stopping server: %v" , err )
280+ }
281+ }
282+ if ! srv .GetConfig ().ServerQuietOutput {
283+ log .Println ("Server stopped" )
284+ }
285+ }()
286+ }
287+
291288func processPipedInput (exec * executor.Executor , term * terminal.Terminal ) {
292289 // Record start time for performance measurement
293290 startTime := time .Now ()
0 commit comments