From e95c2344b8f2831266bd47b97c4d3b4961d6edb2 Mon Sep 17 00:00:00 2001 From: johnnyfish Date: Mon, 6 Apr 2026 18:09:42 +0300 Subject: [PATCH] fix: add apps get command with server-side hint passthrough --- cmd/onecli/apps.go | 50 +++++++++++++++++++++++++++++++++++++++++--- cmd/onecli/help.go | 3 +++ internal/api/apps.go | 12 ++++++++++- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/cmd/onecli/apps.go b/cmd/onecli/apps.go index f37ad73..189de7b 100644 --- a/cmd/onecli/apps.go +++ b/cmd/onecli/apps.go @@ -9,9 +9,16 @@ import ( "github.com/onecli/onecli-cli/pkg/validate" ) +// configureResult is the structured response after configuring an app. +type configureResult struct { + App string `json:"app"` + Status string `json:"status"` +} + // AppsCmd is the `onecli apps` command group. type AppsCmd struct { List AppsListCmd `cmd:"" help:"List all apps with config and connection status."` + Get AppsGetCmd `cmd:"" help:"Get a single app with setup guidance."` Configure AppsConfigureCmd `cmd:"" help:"Save OAuth credentials (BYOC) for a provider."` Remove AppsRemoveCmd `cmd:"" help:"Remove OAuth credentials for a provider."` Disconnect AppsDisconnectCmd `cmd:"" help:"Disconnect an app connection."` @@ -42,6 +49,34 @@ func (c *AppsListCmd) Run(out *output.Writer) error { return out.WriteFiltered(apps, c.Fields) } +// AppsGetCmd is `onecli apps get`. +type AppsGetCmd struct { + Provider string `required:"" help:"Provider name (e.g. 'github', 'gmail')."` + Fields string `optional:"" help:"Comma-separated list of fields to include in output."` +} + +func (c *AppsGetCmd) Run(out *output.Writer) error { + if err := validate.ResourceID(c.Provider); err != nil { + return fmt.Errorf("invalid provider: %w", err) + } + + client, err := newClient() + if err != nil { + return err + } + app, err := client.GetApp(newContext(), c.Provider) + if err != nil { + return err + } + + if app.Hint != "" { + out.SetHint(app.Hint) + app.Hint = "" + } + + return out.WriteFiltered(app, c.Fields) +} + // AppsConfigureCmd is `onecli apps configure`. type AppsConfigureCmd struct { Provider string `required:"" help:"Provider name (e.g. 'github', 'gmail')."` @@ -85,9 +120,18 @@ func (c *AppsConfigureCmd) Run(out *output.Writer) error { return err } - return out.Write(map[string]string{ - "status": "configured", - "provider": c.Provider, + app, err := client.GetApp(newContext(), c.Provider) + if err != nil { + return err + } + + if app.Hint != "" { + out.SetHint(app.Hint) + } + + return out.Write(configureResult{ + App: c.Provider, + Status: "configured", }) } diff --git a/cmd/onecli/help.go b/cmd/onecli/help.go index 73fc5d3..7b42bc4 100644 --- a/cmd/onecli/help.go +++ b/cmd/onecli/help.go @@ -80,6 +80,9 @@ func (cmd *HelpCmd) Run(out *output.Writer) error { {Name: "--id", Required: true, Description: "ID of the secret to delete."}, }}, {Name: "apps list", Description: "List all apps with config and connection status."}, + {Name: "apps get", Description: "Get a single app with setup guidance.", Args: []ArgInfo{ + {Name: "--provider", Required: true, Description: "Provider name (e.g. 'github', 'gmail')."}, + }}, {Name: "apps configure", Description: "Save OAuth credentials (BYOC) for a provider.", Args: []ArgInfo{ {Name: "--provider", Required: true, Description: "Provider name (e.g. 'github', 'gmail')."}, {Name: "--client-id", Required: true, Description: "OAuth client ID."}, diff --git a/internal/api/apps.go b/internal/api/apps.go index 7df68cc..15cc74f 100644 --- a/internal/api/apps.go +++ b/internal/api/apps.go @@ -6,7 +6,7 @@ import ( "net/http" ) -// App represents an app from the unified /api/apps listing. +// App represents an app from the /api/apps endpoints. type App struct { ID string `json:"id"` Name string `json:"name"` @@ -15,6 +15,7 @@ type App struct { Configurable bool `json:"configurable"` Config *AppConfig `json:"config"` Connection *AppConnection `json:"connection"` + Hint string `json:"hint,omitempty"` } // AppConfig is the BYOC credential configuration status. @@ -45,6 +46,15 @@ func (c *Client) ListApps(ctx context.Context) ([]App, error) { return apps, nil } +// GetApp returns a single app by provider name. +func (c *Client) GetApp(ctx context.Context, provider string) (*App, error) { + var app App + if err := c.do(ctx, http.MethodGet, "/api/apps/"+provider, nil, &app); err != nil { + return nil, fmt.Errorf("getting app: %w", err) + } + return &app, nil +} + // ConfigureApp saves BYOC credentials for a provider. func (c *Client) ConfigureApp(ctx context.Context, provider string, input ConfigAppInput) error { var resp SuccessResponse