4
4
"context"
5
5
"fmt"
6
6
"os"
7
- "os/exec"
8
7
"strings"
9
8
10
9
"github.com/abiosoft/ishell/v2"
@@ -29,7 +28,8 @@ func main() {
29
28
30
29
cfg := & config.Config {}
31
30
32
- rootCmd .PersistentFlags ().StringVar (& cfg .APIURL , "api-url" , "http://localhost:8083/api" , "API URL" )
31
+ rootCmd .PersistentFlags ().StringVar (& cfg .KAgentURL , "kagent-url" , "http://localhost:8083" , "KAgent URL" )
32
+ // rootCmd.PersistentFlags().StringVar(&cfg.UserID, "user-id", "admin@kagent.dev", "User ID")
33
33
rootCmd .PersistentFlags ().StringVarP (& cfg .Namespace , "namespace" , "n" , "kagent" , "Namespace" )
34
34
rootCmd .PersistentFlags ().StringVarP (& cfg .OutputFormat , "output-format" , "o" , "table" , "Output format" )
35
35
rootCmd .PersistentFlags ().BoolVarP (& cfg .Verbose , "verbose" , "v" , false , "Verbose output" )
@@ -62,6 +62,7 @@ func main() {
62
62
Run : func (cmd * cobra.Command , args []string ) {
63
63
cli .InvokeCmd (cmd .Context (), invokeCfg )
64
64
},
65
+ Example : `kagent invoke --agent "k8s-agent" --task "Get all the pods in the kagent namespace"` ,
65
66
}
66
67
67
68
invokeCmd .Flags ().StringVarP (& invokeCfg .Task , "task" , "t" , "" , "Task" )
@@ -77,9 +78,13 @@ func main() {
77
78
Short : "Generate a bug report" ,
78
79
Long : `Generate a bug report` ,
79
80
Run : func (cmd * cobra.Command , args []string ) {
80
- client := client .New (cfg .APIURL )
81
+ client := client .New (cfg .KAgentURL )
81
82
if err := cli .CheckServerConnection (client ); err != nil {
82
- pf := cli .NewPortForward (ctx , cfg )
83
+ pf , err := cli .NewPortForward (ctx , cfg )
84
+ if err != nil {
85
+ fmt .Fprintf (os .Stderr , "Error starting port-forward: %v\n " , err )
86
+ return
87
+ }
83
88
defer pf .Stop ()
84
89
}
85
90
cli .BugReportCmd (cfg )
@@ -91,9 +96,13 @@ func main() {
91
96
Short : "Print the kagent version" ,
92
97
Long : `Print the kagent version` ,
93
98
Run : func (cmd * cobra.Command , args []string ) {
94
- client := client .New (cfg .APIURL )
99
+ client := client .New (cfg .KAgentURL )
95
100
if err := cli .CheckServerConnection (client ); err != nil {
96
- pf := cli .NewPortForward (ctx , cfg )
101
+ pf , err := cli .NewPortForward (ctx , cfg )
102
+ if err != nil {
103
+ fmt .Fprintf (os .Stderr , "Error starting port-forward: %v\n " , err )
104
+ return
105
+ }
97
106
defer pf .Stop ()
98
107
}
99
108
cli .VersionCmd (cfg )
@@ -125,9 +134,13 @@ func main() {
125
134
Short : "Get a session or list all sessions" ,
126
135
Long : `Get a session by ID or list all sessions` ,
127
136
Run : func (cmd * cobra.Command , args []string ) {
128
- client := client .New (cfg .APIURL )
137
+ client := client .New (cfg .KAgentURL )
129
138
if err := cli .CheckServerConnection (client ); err != nil {
130
- pf := cli .NewPortForward (ctx , cfg )
139
+ pf , err := cli .NewPortForward (ctx , cfg )
140
+ if err != nil {
141
+ fmt .Fprintf (os .Stderr , "Error starting port-forward: %v\n " , err )
142
+ return
143
+ }
131
144
defer pf .Stop ()
132
145
}
133
146
resourceName := ""
@@ -143,9 +156,12 @@ func main() {
143
156
Short : "Get an agent or list all agents" ,
144
157
Long : `Get an agent by name or list all agents` ,
145
158
Run : func (cmd * cobra.Command , args []string ) {
146
- client := client .New (cfg .APIURL )
159
+ client := client .New (cfg .KAgentURL )
147
160
if err := cli .CheckServerConnection (client ); err != nil {
148
- pf := cli .NewPortForward (ctx , cfg )
161
+ pf , err := cli .NewPortForward (ctx , cfg )
162
+ if err != nil {
163
+ return
164
+ }
149
165
defer pf .Stop ()
150
166
}
151
167
resourceName := ""
@@ -161,9 +177,13 @@ func main() {
161
177
Short : "Get tools" ,
162
178
Long : `List all available tools` ,
163
179
Run : func (cmd * cobra.Command , args []string ) {
164
- client := client .New (cfg .APIURL )
180
+ client := client .New (cfg .KAgentURL )
165
181
if err := cli .CheckServerConnection (client ); err != nil {
166
- pf := cli .NewPortForward (ctx , cfg )
182
+ pf , err := cli .NewPortForward (ctx , cfg )
183
+ if err != nil {
184
+ fmt .Fprintf (os .Stderr , "Error starting port-forward: %v\n " , err )
185
+ return
186
+ }
167
187
defer pf .Stop ()
168
188
}
169
189
cli .GetToolCmd (cfg )
@@ -186,34 +206,34 @@ func main() {
186
206
187
207
}
188
208
209
+ const (
210
+ portForwardKey = "[port-forward]"
211
+ )
212
+
189
213
func runInteractive () {
190
214
cfg , err := config .Get ()
191
215
if err != nil {
192
216
fmt .Fprintf (os .Stderr , "Error getting config: %v\n " , err )
193
217
os .Exit (1 )
194
218
}
195
219
196
- client := client .New (cfg .APIURL , client .WithUserID ("admin@kagent.dev" ))
220
+ client := client .New (cfg .KAgentURL , client .WithUserID ("admin@kagent.dev" ))
197
221
ctx , cancel := context .WithCancel (context .Background ())
198
- cmd := exec .CommandContext (ctx , "kubectl" , "-n" , "kagent" , "port-forward" , "service/kagent" , "8081:8081" )
199
- // Error connecting to server, port-forward the server
200
- go func () {
201
- if err := cmd .Start (); err != nil {
222
+ defer cancel ()
223
+
224
+ // Start port forward and ensure it is healthy.
225
+ var pf * cli.PortForward
226
+ hasPortForward := true
227
+ if err := cli .CheckServerConnection (client ); err != nil {
228
+ pf , err = cli .NewPortForward (ctx , cfg )
229
+ if err != nil {
230
+ // For interactive mode, we don't want to exit the program if the port-forward fails.
231
+ // It is possible to open the interactive shell while kagent is not installed, which would mean that we can't port-forward.
232
+
202
233
fmt .Fprintf (os .Stderr , "Error starting port-forward: %v\n " , err )
203
- os . Exit ( 1 )
234
+ hasPortForward = false
204
235
}
205
- }()
206
- // Ensure the context is cancelled when the shell is closed
207
- defer func () {
208
- cancel ()
209
- // cmd.Wait()
210
- if err := cmd .Wait (); err != nil {
211
- // These 2 errors are expected
212
- if ! strings .Contains (err .Error (), "signal: killed" ) && ! strings .Contains (err .Error (), "exec: not started" ) {
213
- fmt .Fprintf (os .Stderr , "Error waiting for port-forward to exit: %v\n " , err )
214
- }
215
- }
216
- }()
236
+ }
217
237
218
238
homeDir , err := os .UserHomeDir ()
219
239
if err != nil {
@@ -224,10 +244,18 @@ func runInteractive() {
224
244
// create new shell.
225
245
// by default, new shell includes 'exit', 'help' and 'clear' commands.
226
246
shell := ishell .New ()
247
+ if pf != nil {
248
+ shell .Set (portForwardKey , pf )
249
+ }
250
+
227
251
config .SetHistoryPath (homeDir , shell )
228
252
if err := shell .ClearScreen (); err != nil {
229
253
fmt .Fprintf (os .Stderr , "Error clearing screen: %v\n " , err )
230
254
}
255
+
256
+ if ! hasPortForward {
257
+ shell .Println (cli .ErrServerConnection )
258
+ }
231
259
shell .Println ("Welcome to kagent CLI. Type 'help' to see available commands." , strings .Repeat (" " , 10 ))
232
260
233
261
config .SetCfg (shell , cfg )
@@ -244,7 +272,7 @@ The available run types are:
244
272
- chat: Start a chat with a kagent agent.
245
273
246
274
Examples:
247
- - run chat [team_name ] -s [session_name]
275
+ - run chat [agent_name ] -s [session_name]
248
276
- run chat
249
277
` ,
250
278
}
@@ -255,12 +283,12 @@ Examples:
255
283
Help : "Start a chat with a kagent agent." ,
256
284
LongHelp : `Start a chat with a kagent agent.
257
285
258
- If no team name is provided, then a list of available teams will be provided to select from.
286
+ If no agent name is provided, then a list of available agents will be provided to select from.
259
287
If no session name is provided, then a new session will be created and the chat will be associated with it.
260
288
261
289
Examples:
262
- - chat [team_name ] -s [session_name]
263
- - chat [team_name ]
290
+ - chat [agent_name ] -s [session_name]
291
+ - chat [agent_name ]
264
292
- chat
265
293
` ,
266
294
Func : func (c * ishell.Context ) {
@@ -393,6 +421,10 @@ Example:
393
421
Aliases : []string {"v" },
394
422
Help : "Print the kagent version." ,
395
423
Func : func (c * ishell.Context ) {
424
+ if err := cli .CheckServerConnection (client ); err != nil {
425
+ c .Println (err )
426
+ return
427
+ }
396
428
cli .VersionCmd (cfg )
397
429
c .SetPrompt (config .BoldBlue ("kagent >> " ))
398
430
},
@@ -404,7 +436,10 @@ Example:
404
436
Help : "Install kagent." ,
405
437
Func : func (c * ishell.Context ) {
406
438
cfg := config .GetCfg (c )
407
- cli .InstallCmd (ctx , cfg )
439
+ if pf := cli .InstallCmd (ctx , cfg ); pf != nil {
440
+ // Set the port-forward to the shell.
441
+ shell .Set (portForwardKey , pf )
442
+ }
408
443
},
409
444
})
410
445
@@ -419,6 +454,11 @@ Example:
419
454
}
420
455
cfg := config .GetCfg (c )
421
456
cli .UninstallCmd (ctx , cfg )
457
+ // Safely stop the port-forward if it is running.
458
+ if pf := shell .Get (portForwardKey ); pf != nil {
459
+ pf .(* cli.PortForward ).Stop ()
460
+ shell .Del (portForwardKey )
461
+ }
422
462
},
423
463
})
424
464
@@ -436,5 +476,11 @@ Example:
436
476
},
437
477
})
438
478
479
+ defer func () {
480
+ if pf := shell .Get (portForwardKey ); pf != nil {
481
+ pf .(* cli.PortForward ).Stop ()
482
+ shell .Del (portForwardKey )
483
+ }
484
+ }()
439
485
shell .Run ()
440
486
}
0 commit comments