Files
WeKnora/cli/cmd/context/list.go
T
nullkey 0e081aec5c feat(cli): --log-level + kb/agent status & check + cross-cutting refactor
Operability surface and the bulk of the jopts→fopts migration:

* --log-level error|warn|info|debug + WEKNORA_LOG_LEVEL env, wired to
  the SDK via client.SetDebugLevel. Invalid --log-level returns FlagError
  (exit 2).
* kb status <kb-id> / kb check <kb-id> verb split (1 HTTP vs 1+N for
  failed_count aggregation).
* agent status <agent-id> / agent check <agent-id> verb split
  (probes kb_scope_all_reachable via 1+N HTTP).
* kb create <name> positional (matches agent create).
* Positional id help strings namespaced (<kb-id> / <agent-id>).
* All auth / context / link / doctor / kb / agent CRUD commands migrated
  to the FormatOptions API.
* root.go Execute(ctx) takes a context so signal-cancellation propagates
  via cmd.Context() into long-running commands.
* Pagination termination uses len(accum) >= total (not page*pageSize)
  so server-capped page sizes do not truncate aggregations.
2026-05-18 11:10:19 +08:00

92 lines
2.6 KiB
Go

package contextcmd
import (
"fmt"
"sort"
"text/tabwriter"
"github.com/spf13/cobra"
"github.com/Tencent/WeKnora/cli/internal/cmdutil"
"github.com/Tencent/WeKnora/cli/internal/config"
"github.com/Tencent/WeKnora/cli/internal/format"
"github.com/Tencent/WeKnora/cli/internal/iostreams"
)
type ListOptions struct{}
// contextListFields enumerates the fields surfaced for `--format json` discovery on
// `context list`. Each entry is a per-context summary row.
var contextListFields = []string{
"name", "host", "user", "current",
}
type listEntry struct {
Name string `json:"name"`
Host string `json:"host"`
User string `json:"user,omitempty"`
Current bool `json:"current"`
}
// NewCmdList builds `weknora context list`. Per-host enumeration with an
// active marker. Reads only config.yaml - no network, no keyring touch.
func NewCmdList(f *cmdutil.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List configured contexts",
Long: `Show every context registered in ~/.config/weknora/config.yaml. The
active context (used by subsequent commands when --context is unset) is
marked with a leading "*". No network requests are issued.
The credential mode (api-key vs password) is intentionally not shown here -
run "weknora auth list" for that. "context list" is the catalog of *where*
the CLI can talk to; "auth list" is the catalog of *how*.`,
Args: cobra.NoArgs,
RunE: func(c *cobra.Command, _ []string) error {
fopts, err := cmdutil.CheckFormatFlag(c)
if err != nil {
return err
}
fopts.ResolveDefault(iostreams.IO.IsStdoutTTY())
return runList(fopts)
},
}
cmdutil.AddFormatFlag(cmd, contextListFields...)
return cmd
}
func runList(fopts *cmdutil.FormatOptions) error {
cfg, err := config.Load()
if err != nil {
return err
}
entries := make([]listEntry, 0, len(cfg.Contexts))
for name, c := range cfg.Contexts {
entries = append(entries, listEntry{
Name: name,
Host: c.Host,
User: c.User,
Current: name == cfg.CurrentContext,
})
}
sort.Slice(entries, func(i, j int) bool { return entries[i].Name < entries[j].Name })
if fopts.WantsJSON() {
return fopts.Emit(iostreams.IO.Out, entries)
}
if len(entries) == 0 {
fmt.Fprintln(iostreams.IO.Out, "No contexts configured. Run `weknora auth login` (or `weknora context add`) to create one.")
return nil
}
tw := tabwriter.NewWriter(iostreams.IO.Out, 0, 0, 2, ' ', 0)
fmt.Fprintln(tw, " NAME\tHOST\tUSER")
for _, e := range entries {
marker := " "
if e.Current {
marker = "* "
}
fmt.Fprintf(tw, "%s%s\t%s\t%s\n", marker, e.Name, e.Host, format.DashIfEmpty(e.User))
}
return tw.Flush()
}