From 0846987906cddfe41b1931dde0abb129794e6dd0 Mon Sep 17 00:00:00 2001 From: Oliver Kwun-Morfitt Date: Sat, 15 Nov 2025 17:31:30 -0500 Subject: [PATCH 1/6] some intial state and ctx for auth --- cli/cmd/root.go | 68 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index dc03e11..98b8c81 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -1,28 +1,84 @@ package cmd import ( + "encoding/json" + "net/http" + "os" + "path/filepath" + "time" + "github.com/alecthomas/kong" ) +type Config struct { + AccessToken string `json:"access_token"` + // maybe APIBaseURL, etc. +} + +type AppContext struct { + Config *Config + HTTPClient *http.Client +} + +type Globals struct { + ConfigPath string `name:"config" help:"Path to config file" default:"${config_path}"` +} + type CLI struct { - // Define your CLI structure here: Top Level Commands + Globals + + // Define your CLI structure here: Top Level Commands Auth AuthCmd `cmd:"" help:"Authentication commands"` Job JobCmd `cmd:"" help:"Job management commands"` // Config ConfigCmd `cmd:"" help:"Configuration commands"` Help HelpCmd `cmd:"" help:"Show help information"` - Config ConfigCmd `cmd:"" help: "Display Cluster Configuration"` + // Config ConfigCmd `cmd:"" help: "Display Cluster Configuration"` +} + +func defaultConfigPath() string { + dir, err := os.UserConfigDir() + if err != nil { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".config", "mist", "config.json") + } + return filepath.Join(dir, "mist", "config.json") +} + +func loadConfig(path string) (*Config, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + var cfg Config + if err := json.Unmarshal(b, &cfg); err != nil { + return nil, err + } + + return &cfg, nil } func Main() { var cli CLI - // Read command-line arguments - ctx := kong.Parse(&cli, + // Read command-line arguments + + appCtx := &AppContext{ + HTTPClient: &http.Client{Timeout: 10 * time.Second}, + } + + kctx := kong.Parse(&cli, kong.Name("mist"), kong.Description("MIST CLI - Manage your MIST jobs and configurations"), kong.UsageOnError(), + kong.Vars{"config_path": defaultConfigPath()}, + kong.Bind(appCtx), ) - err := ctx.Run() - ctx.FatalIfErrorf(err) + if cfg, err := loadConfig(cli.ConfigPath); err == nil { + appCtx.Config = cfg + } + + err := kctx.Run() + kctx.FatalIfErrorf(err) // fmt.Println("Command executed successfully") } From 7095f52cdc4f60ef959dd005ad51541a62d3ddc8 Mon Sep 17 00:00:00 2001 From: Oliver Kwun-Morfitt Date: Sat, 15 Nov 2025 19:37:40 -0500 Subject: [PATCH 2/6] added app context to every command --- cli/cmd/auth_login.go | 2 +- cli/cmd/config.go | 20 +++++++++----------- cli/cmd/job_cancel.go | 24 +++++++++++------------- cli/cmd/job_list.go | 2 +- cli/cmd/job_status.go | 2 +- cli/cmd/job_submit.go | 3 +-- 6 files changed, 24 insertions(+), 29 deletions(-) diff --git a/cli/cmd/auth_login.go b/cli/cmd/auth_login.go index 1f24521..f1230bb 100644 --- a/cli/cmd/auth_login.go +++ b/cli/cmd/auth_login.go @@ -23,7 +23,7 @@ func verifyUser(username, password string) error { // TODO: Figure out how to handle password input without exposing it in the terminal historyn (go get golang.org/x/term) // TODO: Where are we storing auth token? Are we getting JWT? -func (l *LoginCmd) Run() error { +func (l *LoginCmd) Run(ctx *AppContext) error { // mist auth login fmt.Print("Username: ") diff --git a/cli/cmd/config.go b/cli/cmd/config.go index acb9ba8..5869954 100644 --- a/cli/cmd/config.go +++ b/cli/cmd/config.go @@ -2,28 +2,26 @@ package cmd import "fmt" - -// Config flags -type ConfigCmd struct{ +// Config flags +type ConfigCmd struct { DefaultCluster string `help:"Set the default compute cluster." optional: ""` - Show bool `help:"Show current configuration."` - + Show bool `help:"Show current configuration."` } -func (h *ConfigCmd) Run() error { - // Some dummy config; Call API or something +func (h *ConfigCmd) Run(ctx *AppContext) error { + // Some dummy config; Call API or something defaultConfig := map[string]string{ "defaultCluster": "AMD-cluster-1", - "region": "us-east", + "region": "us-east", } - if h.Show && h.DefaultCluster!= "" { + if h.Show && h.DefaultCluster != "" { fmt.Printf("Cannot use --show and --default-cluster together") return nil } if h.DefaultCluster != "" { - // This is not actually set. + // This is not actually set. fmt.Printf("Setting default cluster to: %s\n", h.DefaultCluster) return nil } @@ -36,7 +34,7 @@ func (h *ConfigCmd) Run() error { return nil } - fmt.Println("No config action specified. Use --help for options.") + fmt.Println("No config action specified. Use --help for options.") return nil } diff --git a/cli/cmd/job_cancel.go b/cli/cmd/job_cancel.go index 446787a..949a885 100644 --- a/cli/cmd/job_cancel.go +++ b/cli/cmd/job_cancel.go @@ -8,13 +8,12 @@ import ( "time" ) - type JobCancelCmd struct { - ID string `arg:"" help:"ID of job you want to cancel"` + ID string `arg:"" help:"ID of job you want to cancel"` } -func (c *JobCancelCmd) Run() error { - // Same Mock data from job list. +func (c *JobCancelCmd) Run(ctx *AppContext) error { + // Same Mock data from job list. jobs := []Job{ { ID: "ID:1", @@ -39,36 +38,35 @@ func (c *JobCancelCmd) Run() error { }, } - // Check if job exists + // Check if job exists if !jobExists(jobs, c.ID) { fmt.Printf("%s does not exist in your jobs.\n", c.ID) fmt.Printf("Use the command \"job list\" for your list of jobs.") - return nil + return nil } - fmt.Printf("Are you sure you want to cancel %s? (y/n): \n", c.ID) reader := bufio.NewReader(os.Stdin) input, _ := reader.ReadString('\n') input = strings.TrimSpace(strings.ToLower(input)) - if input == "y" || input == "yes"{ + if input == "y" || input == "yes" { fmt.Println("Confirmed, proceeding job cancellation....") - // Confirmed job cancellation logic + // Confirmed job cancellation logic fmt.Println("Cancelling job with ID:", c.ID) fmt.Printf("Job cancelled successfully with ID: %s\n", c.ID) return nil - } else if input == "n" || input == "no"{ + } else if input == "n" || input == "no" { fmt.Println("Cancelled.") return nil - } else{ + } else { fmt.Println("Invalid response.") return nil } - return nil + return nil -} \ No newline at end of file +} diff --git a/cli/cmd/job_list.go b/cli/cmd/job_list.go index 118df0e..9e4787d 100644 --- a/cli/cmd/job_list.go +++ b/cli/cmd/job_list.go @@ -19,7 +19,7 @@ type Job struct { CreatedAt time.Time } -func (l *ListCmd) Run() error { +func (l *ListCmd) Run(ctx *AppContext) error { // Mock data - pull from API in real implementation jobs := []Job{ { diff --git a/cli/cmd/job_status.go b/cli/cmd/job_status.go index cff9187..20634c8 100644 --- a/cli/cmd/job_status.go +++ b/cli/cmd/job_status.go @@ -11,7 +11,7 @@ type JobStatusCmd struct { ID string `arg:"" help:"The ID of the job to check the status for"` } -func (j *JobStatusCmd) Run() error { +func (j *JobStatusCmd) Run(ctx *AppContext) error { // Mock data - pull from API in real implementation jobs := []Job{{ ID: "ID:1", diff --git a/cli/cmd/job_submit.go b/cli/cmd/job_submit.go index d090934..22b793f 100644 --- a/cli/cmd/job_submit.go +++ b/cli/cmd/job_submit.go @@ -12,8 +12,7 @@ type JobSubmitCmd struct { Compute string `help:"Type of compute required for the job: AMD|TT|CPU" default:"AMD"` } - -func (j *JobSubmitCmd) Run() error { +func (j *JobSubmitCmd) Run(ctx *AppContext) error { // mist job submit