Documentation
¶
Overview ¶
Package cli is the command-line client (design 04 §4).
A client of the API and nothing more (R-261). The CLI must not have a capability the API lacks, and the way to keep that true is to give it no access to anything else: this package talks HTTP and does not import internal/core at all. If a command here needs something the API cannot do, the answer is an endpoint, not a shortcut.
Index ¶
- Constants
- Variables
- func Commands() []*cobra.Command
- func ExitCodeOf(err error) int
- func MCPCommand() *cobra.Command
- func PackDirectory(dir string) ([]byte, int, error)
- func SaveCredentials(c Credentials) error
- func SelfUpdateCmd() *cobra.Command
- type APIError
- type Client
- func (c *Client) Do(method, path string, body, out any) error
- func (c *Client) Exec(ctx context.Context, opts ExecOptions) error
- func (c *Client) Stream(method, path string, body any) (io.ReadCloser, error)
- func (c *Client) UploadIcon(appID string, image []byte) error
- func (c *Client) UploadSource(appID string, archive []byte) error
- type Credentials
- type ExecOptions
- type ExitCode
Constants ¶
const ( EnvServer = "PANDO_SERVER" EnvToken = "PANDO_TOKEN" )
The environment a machine authenticates with.
`pando login` is for a person at a terminal: it stores a token in a file under their home directory, which is the right place for it and the wrong place for CI, a container, or an MCP client's configuration block. Those have an environment and no home directory worth writing to, and without this the only way to use a minted token was to write the credentials file by hand.
Named constants because the reference quotes them: `docs/cli.md` and the console's API screen are generated, and a documented variable name that nothing reads is the drift this whole mechanism exists to prevent.
Variables ¶
var ErrNotLoggedIn = errors.New("not logged in — run `pando login` first, or set PANDO_SERVER and PANDO_TOKEN")
ErrNotLoggedIn is returned when there is no stored credential.
var Version = "dev"
Version is this CLI's version, set by main from the release build's stamp.
Functions ¶
func Commands ¶
Commands returns the client half of the CLI (design 04 §4).
Every one of these is a wrapper over an endpoint. That is the constraint R-261 puts on this package and the reason it reads repetitively: a command that did something the API cannot do would be a capability the console and MCP could never have.
func ExitCodeOf ¶
ExitCodeOf returns the code err asks the process to exit with: its own, if it carries one, and otherwise 1.
func MCPCommand ¶
MCPCommand runs the MCP server over stdio (R-262, design 04 §3).
In the CLI rather than the server because that is where the credential is: an agent runs this on its own machine with its own token, and the token is what makes it a principal. A server-side MCP endpoint would need its own authentication and would be a second way in.
func PackDirectory ¶
PackDirectory writes dir as a gzipped tar, returning the archive and how many files it holds.
func SaveCredentials ¶
func SaveCredentials(c Credentials) error
SaveCredentials writes the token, readable only by its owner.
func SelfUpdateCmd ¶
SelfUpdateCmd is `pando self-update`. Beside `version` rather than among the API's commands: it acts on this binary, not on an installation (R-261).
Types ¶
type APIError ¶
type APIError struct {
Status int
Code string `json:"code"`
Message string `json:"message"`
Remedy string `json:"remedy,omitempty"`
ReqID string `json:"request_id,omitempty"`
// Details is the envelope's structured part, for a command that turns a
// refusal into the flag that answers it.
Details map[string]any `json:"details,omitempty"`
}
APIError is the server's error envelope (design 00 §3.2).
Rendered as written. The messages are held to the R-105 standard — self contained, actionable, pasteable into an assistant — and paraphrasing them here would undo that at the last step.
type Client ¶
type Client struct {
BaseURL string
Token string
HTTP *http.Client
// Warn receives the version-skew warning (R-353). Nil says nothing.
Warn io.Writer
}
Client talks to a Pando server.
func New ¶
New builds a client from stored credentials, with the server URL overridable so a script can point at a different install without logging in again.
func (*Client) Exec ¶
func (c *Client) Exec(ctx context.Context, opts ExecOptions) error
Exec opens a terminal inside a running workload (R-086).
Returns the command's exit status so `pando exec app -- false` can be used in a script the way ssh is. A transport failure is a Go error; a non-zero exit inside the container is an exitError and not a failure of this command.
func (*Client) UploadIcon ¶
UploadIcon sets an app's tile image (R-340). The server decides what the bytes are; the content type sent is only a courtesy.
type Credentials ¶
type Credentials struct {
URL string `json:"url"`
Token string `json:"token"`
User string `json:"user,omitempty"`
}
Credentials are what `pando login` stores.
A token rather than a session cookie: a session is bound to a browser's lifetime and revoked on a password change, which is right for a browser and wrong for a script that runs at 3am. The token is delegated, so it acts as its owner and holds nothing they do not (R-058).
func LoadCredentials ¶
func LoadCredentials() (Credentials, error)
LoadCredentials reads the stored token.
type ExecOptions ¶
type ExecOptions struct {
AppID string
Workload string
Command []string
// In, Out and Err are the local ends of the terminal. Fields rather than
// os.Stdin directly so the failure path can be tested without a tty.
In *os.File
Out io.Writer
Err io.Writer
}
ExecOptions is one terminal session.
type ExitCode ¶
ExitCode is an error that asks the process to exit with a particular code.
For the outcomes a script needs to tell apart without reading the output: `pando app detection --wait` exits 2 when a person has to answer questions before the app can be accepted, and 1 when detection failed or was blocked.