f2e8e3f56c
Survey of 10 mainstream CLIs (gh, lark, stripe, vercel, supabase, aws, azure, gcloud, openai/codex, github-copilot-cli) showed env-gated per-command --help blurbs are a Stripe-only pattern; gh uses env detect for telemetry only, and lark relies on installed agent Skills + MCP. Our cmd/mcp/serve already covers the dominant 2025/26 path, so internal/aiclient/ (136 LOC + 38 callsites) is net maintenance burden without precedent. - Drop internal/aiclient/ entirely (annotations + detect + tests) - Remove 38 SetAgentHelp callsites + agentAwareHelpFunc / SetHelpFunc wiring in cmd/root.go - Migrate 4 command-level rules to standard Long help (visible to all, not env-gated): doc upload mode mutex, kb edit at-least-one, kb pin idempotent, search chunks channel mutex - Rewrite AGENTS.md as a developer guide (gh-style 6 H2 / 167 lines): audience preamble + Build / Architecture / Command Structure / Testing / Code Style / Error Handling. Drops sections absent in surveyed projects (Commit & PR Conventions, Who Uses This CLI) - Clean 14 internal doc refs (ADR-N, spec §X, v0.X) in source comments and docs that pointed at docs/superpowers/ — that directory is local-only / uncommitted, so refs are dead for outside readers - Drop forward-looking "once v0.2 ships" from README
108 lines
3.1 KiB
Go
108 lines
3.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/Tencent/WeKnora/cli/internal/cmdutil"
|
|
"github.com/Tencent/WeKnora/cli/internal/iostreams"
|
|
sdk "github.com/Tencent/WeKnora/client"
|
|
)
|
|
|
|
// authStatusFields enumerates the fields surfaced for `--json` discovery
|
|
// on `auth status`. Single-resource shape: filter applies to data itself.
|
|
var authStatusFields = []string{
|
|
"context", "user_id", "email", "tenant_id", "tenant_name",
|
|
}
|
|
|
|
// StatusService is the narrow SDK surface auth status depends on.
|
|
type StatusService interface {
|
|
GetCurrentUser(ctx context.Context) (*sdk.CurrentUserResponse, error)
|
|
}
|
|
|
|
// statusResult is the typed payload emitted by `--json`.
|
|
type statusResult struct {
|
|
Context string `json:"context"`
|
|
UserID string `json:"user_id,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
TenantID uint64 `json:"tenant_id,omitempty"`
|
|
TenantName string `json:"tenant_name,omitempty"`
|
|
}
|
|
|
|
// NewCmdStatus builds the `weknora auth status` command.
|
|
func NewCmdStatus(f *cmdutil.Factory) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "status",
|
|
Short: "Show the active context, principal, and token state",
|
|
Long: `Live-check the active credential by calling /auth/me. Reports the user
|
|
and tenant the server resolves the credential to.
|
|
|
|
Exits with auth.unauthenticated when the token is invalid or missing - run
|
|
` + "`weknora auth login`" + ` (or ` + "`auth refresh`" + ` for JWT contexts) to recover.
|
|
For JWT contexts the SDK transparently refreshes on 401, so this command
|
|
usually only surfaces a hard auth failure.`,
|
|
Args: cobra.NoArgs,
|
|
RunE: func(c *cobra.Command, args []string) error {
|
|
jopts, err := cmdutil.CheckJSONFlags(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cli, err := f.Client()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return runStatus(c.Context(), jopts, f, cli)
|
|
},
|
|
}
|
|
cmdutil.AddJSONFlags(cmd, authStatusFields)
|
|
return cmd
|
|
}
|
|
|
|
func runStatus(ctx context.Context, jopts *cmdutil.JSONOptions, f *cmdutil.Factory, svc StatusService) error {
|
|
if svc == nil {
|
|
return cmdutil.NewError(cmdutil.CodeAuthUnauthenticated, "no SDK client available; run `weknora auth login`")
|
|
}
|
|
resp, err := svc.GetCurrentUser(ctx)
|
|
if err != nil {
|
|
return cmdutil.WrapHTTP(err, "fetch current user")
|
|
}
|
|
user := resp.Data.User
|
|
tenant := resp.Data.Tenant
|
|
|
|
cfg, err := f.Config()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if jopts.Enabled() {
|
|
result := statusResult{Context: cfg.CurrentContext}
|
|
if user != nil {
|
|
result.UserID = user.ID
|
|
result.Email = user.Email
|
|
result.TenantID = user.TenantID
|
|
}
|
|
if tenant != nil {
|
|
result.TenantName = tenant.Name
|
|
}
|
|
return jopts.Emit(iostreams.IO.Out, result)
|
|
}
|
|
|
|
host := ""
|
|
if c, ok := cfg.Contexts[cfg.CurrentContext]; ok {
|
|
host = c.Host
|
|
}
|
|
fmt.Fprintf(iostreams.IO.Out, "context: %s\n", cfg.CurrentContext)
|
|
fmt.Fprintf(iostreams.IO.Out, "host: %s\n", host)
|
|
if user != nil {
|
|
fmt.Fprintf(iostreams.IO.Out, "user: %s (%s)\n", user.Email, user.ID)
|
|
fmt.Fprintf(iostreams.IO.Out, "tenant: %d", user.TenantID)
|
|
if tenant != nil {
|
|
fmt.Fprintf(iostreams.IO.Out, " (%s)", tenant.Name)
|
|
}
|
|
fmt.Fprintln(iostreams.IO.Out)
|
|
}
|
|
return nil
|
|
}
|