Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

176 lines
5.3 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/spf13/cobra"
"github.com/zzet/gortex/internal/daemon"
)
var (
daemonServerAddURL string
daemonServerAddDefault bool
daemonServerAddAuthToken string
daemonServerAddAuthTokenEnv string
daemonServerAddWorkspaces []string
daemonServerAddReadOnly bool
)
var daemonServerCmd = &cobra.Command{
Use: "server",
Short: "Manage the multi-server roster in ~/.gortex/servers.toml",
Long: `Maintain ~/.gortex/servers.toml — the multi-server roster the daemon
and the gortex server load on startup to wire up local-fast-path vs
proxy routing.
The file holds one [[server]] block per reachable Gortex server: a
local socket, a remote HTTPS endpoint, etc. Adding or removing an entry
is applied to a running daemon live (no restart); if the daemon is down
the change simply takes effect on its next start.`,
}
var daemonServerAddCmd = &cobra.Command{
Use: "add <slug>",
Short: "Add a server entry to ~/.gortex/servers.toml",
Long: `Append a new server to the roster. Slug must be unique. URL accepts
http://, https://, or unix:///path/to.sock. Auth: pass --auth-token-env
(preferred) to point at an environment variable, or --auth-token to
write the literal value into the file.
If --default is set and another entry already has default=true, the
command fails — remove or unflag the existing default first.`,
Args: cobra.ExactArgs(1),
RunE: runDaemonServerAdd,
SilenceUsage: true,
}
var daemonServerRemoveCmd = &cobra.Command{
Use: "remove <slug>",
Aliases: []string{"rm"},
Short: "Remove a server entry from ~/.gortex/servers.toml",
Args: cobra.ExactArgs(1),
RunE: runDaemonServerRemove,
SilenceUsage: true,
}
var daemonServerListCmd = &cobra.Command{
Use: "list",
Short: "Print the current ~/.gortex/servers.toml roster",
RunE: runDaemonServerList,
SilenceUsage: true,
}
func init() {
daemonServerAddCmd.Flags().StringVar(&daemonServerAddURL, "url", "", "server URL (http://, https://, or unix:///path) — required")
daemonServerAddCmd.Flags().BoolVar(&daemonServerAddDefault, "default", false, "mark this entry as the default server")
daemonServerAddCmd.Flags().StringVar(&daemonServerAddAuthToken, "auth-token", "", "literal bearer token (consider --auth-token-env instead)")
daemonServerAddCmd.Flags().StringVar(&daemonServerAddAuthTokenEnv, "auth-token-env", "", "env-var name the daemon reads at request time")
daemonServerAddCmd.Flags().StringSliceVar(&daemonServerAddWorkspaces, "workspaces", nil, "pre-declared workspace slugs (comma-separated)")
daemonServerAddCmd.Flags().BoolVar(&daemonServerAddReadOnly, "read-only", false, "mark this remote read-only (no write tools routed to it)")
_ = daemonServerAddCmd.MarkFlagRequired("url")
daemonServerCmd.AddCommand(daemonServerAddCmd)
daemonServerCmd.AddCommand(daemonServerRemoveCmd)
daemonServerCmd.AddCommand(daemonServerListCmd)
daemonCmd.AddCommand(daemonServerCmd)
}
func runDaemonServerAdd(_ *cobra.Command, args []string) error {
slug := args[0]
cfg, err := daemon.LoadServersConfig("")
if err != nil {
return err
}
if cfg == nil {
cfg = &daemon.ServersConfig{}
}
entry := daemon.ServerEntry{
Slug: slug,
URL: daemonServerAddURL,
AuthToken: daemonServerAddAuthToken,
AuthTokenEnv: daemonServerAddAuthTokenEnv,
Workspaces: daemonServerAddWorkspaces,
Default: daemonServerAddDefault,
ReadOnly: daemonServerAddReadOnly,
}
if err := cfg.AddServer(entry); err != nil {
return err
}
if err := cfg.Save(""); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "[gortex] added server %q (%s) to %s\n", slug, daemonServerAddURL, daemon.ServersConfigPath())
proxyApplyToRunningDaemon()
return nil
}
func runDaemonServerRemove(_ *cobra.Command, args []string) error {
slug := args[0]
cfg, err := daemon.LoadServersConfig("")
if err != nil {
return err
}
if cfg == nil {
cfg = &daemon.ServersConfig{}
}
removed, err := cfg.RemoveServer(slug)
if err != nil {
return err
}
if !removed {
fmt.Fprintf(os.Stderr, "[gortex] no server with slug %q in %s — nothing to remove\n", slug, daemon.ServersConfigPath())
return nil
}
if err := cfg.Save(""); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "[gortex] removed server %q from %s\n", slug, daemon.ServersConfigPath())
proxyApplyToRunningDaemon()
return nil
}
func runDaemonServerList(_ *cobra.Command, _ []string) error {
cfg, err := daemon.LoadServersConfig("")
if err != nil {
return err
}
if cfg == nil || len(cfg.Server) == 0 {
fmt.Fprintf(os.Stderr, "[gortex] no servers configured (%s is empty or missing)\n", daemon.ServersConfigPath())
return nil
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetStyle(table.StyleLight)
t.Style().Format.Header = text.FormatDefault
t.AppendHeader(table.Row{"slug", "url", "default", "auth", "workspaces"})
yesno := func(b bool) string {
if b {
return "yes"
}
return ""
}
for _, s := range cfg.Server {
auth := ""
switch {
case s.AuthTokenEnv != "":
auth = "env:" + s.AuthTokenEnv
case s.AuthToken != "":
auth = "literal"
}
t.AppendRow(table.Row{
s.Slug,
s.URL,
yesno(s.Default),
auth,
strings.Join(s.Workspaces, ", "),
})
}
t.Render()
return nil
}