remote

package
v0.0.58 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package remote implements the client-side wiring for targeting a klaus-gateway instead of a locally-running klaus container.

The Target type composes the request URL, the routing headers (X-Klaus-Channel, X-Klaus-Channel-ID, X-Klaus-User-ID, X-Klaus-Thread-ID), and the bearer token used by `klausctl run`, `klausctl prompt`, and `klausctl messages` when `--remote=URL` is set.

Index

Constants

View Source
const (
	// ChannelHeader identifies where a gateway request originated.
	ChannelHeader = "X-Klaus-Channel"
	// ChannelIDHeader scopes the channel to a specific identity (hostname).
	ChannelIDHeader = "X-Klaus-Channel-ID"
	// UserIDHeader carries the authenticated user identity.
	UserIDHeader = "X-Klaus-User-ID"
	// ThreadIDHeader carries the conversation/session identity.
	ThreadIDHeader = "X-Klaus-Thread-ID"

	// ChannelCLI is the value sent on ChannelHeader for klausctl CLI calls.
	ChannelCLI = "cli"
)

Variables

This section is empty.

Functions

func DefaultSession

func DefaultSession() string

DefaultSession returns the stable default thread id derived from the current working directory. Same directory -> same thread id across invocations, so a user running `klausctl prompt --remote=...` twice from the same repo reuses the same conversation thread.

func NormalizeBaseURL

func NormalizeBaseURL(raw string) (string, error)

NormalizeBaseURL validates a remote URL and strips any trailing slash and any `/v1` suffix so path composition stays predictable.

func ResolveChannelID

func ResolveChannelID() string

ResolveChannelID returns the host identity used in X-Klaus-Channel-ID. Falls back to "unknown" when the hostname cannot be resolved.

func ResolveUserID

func ResolveUserID(bearer string) string

ResolveUserID extracts the user identity used in X-Klaus-User-ID. It prefers the `sub` claim from the bearer token JWT (if the token parses cleanly), falling back to $USER, then the current uid, then "unknown".

Types

type AuthRecord

type AuthRecord struct {
	// ServerURL is the remote klaus-gateway root (normalized).
	ServerURL string `yaml:"server_url"`
	// Issuer is the OAuth authorization server issuer URL (from discovery).
	Issuer string `yaml:"issuer"`
	// AccessToken is the current access token.
	AccessToken string `yaml:"access_token"`
	// TokenType is the token type, typically "Bearer".
	TokenType string `yaml:"token_type,omitempty"`
	// RefreshToken is used to mint a new access token without re-login.
	RefreshToken string `yaml:"refresh_token,omitempty"`
	// ExpiresAt is the absolute expiry time of AccessToken.
	ExpiresAt time.Time `yaml:"expires_at,omitempty"`
	// Scope is the scope granted for the access token, if reported.
	Scope string `yaml:"scope,omitempty"`
	// TokenEndpoint is the OAuth token endpoint (cached so refresh can
	// proceed without repeating discovery).
	TokenEndpoint string `yaml:"token_endpoint,omitempty"`
	// ClientID is the OAuth client identifier used during the original
	// authorization (typically the CIMD URL).
	ClientID string `yaml:"client_id,omitempty"`
}

AuthRecord is the per-host credential record persisted on disk.

ExpiresAt is the absolute expiry of AccessToken. When the access token is about to expire, callers should refresh using RefreshToken.

func Login

func Login(ctx context.Context, store *AuthStore, serverURL string, opts LoginOptions) (*AuthRecord, error)

Login performs browser-based OAuth login against a remote klaus-gateway and persists the resulting credentials in the given AuthStore. It reuses the pkg/oauth helpers for discovery/PKCE/callback and implements the authorization-URL build + token exchange locally so the resulting AuthRecord captures the token endpoint and client id needed for later refresh-on-401 in pkg/remote/refresh.go.

func Refresh

func Refresh(ctx context.Context, httpClient *http.Client, rec AuthRecord) (AuthRecord, error)

Refresh exchanges the refresh token stored in rec for a new access token via the cached token endpoint. The updated record (same fields, new AccessToken/ExpiresAt/RefreshToken) is returned; callers are responsible for persisting it with AuthStore.Put.

If the server rejects the refresh (401/invalid_grant) Refresh returns *ErrReloginRequired so the caller can surface a "re-run auth login" hint to the user.

func (*AuthRecord) IsExpired

func (r *AuthRecord) IsExpired(leeway time.Duration) bool

IsExpired reports whether the access token is expired or will expire within the given leeway. Zero ExpiresAt is treated as non-expiring.

type AuthStore

type AuthStore struct {
	// contains filtered or unexported fields
}

AuthStore manages host-keyed OAuth records at ~/.config/klausctl/auth/. Files are written with 0600 and the parent directory with 0700.

func NewAuthStore

func NewAuthStore(dir string) *AuthStore

NewAuthStore returns an AuthStore backed by the given directory.

func (*AuthStore) Delete

func (s *AuthStore) Delete(serverURL string) error

Delete removes the record for the given server URL. Missing files are treated as success.

func (*AuthStore) Dir

func (s *AuthStore) Dir() string

Dir returns the directory backing the store.

func (*AuthStore) Get

func (s *AuthStore) Get(serverURL string) (*AuthRecord, error)

Get returns the stored record for the given server URL, or nil when none exists. Only read errors other than ENOENT surface as errors.

func (*AuthStore) List

func (s *AuthStore) List() ([]AuthRecord, error)

List returns all stored records sorted by server URL.

func (*AuthStore) Put

func (s *AuthStore) Put(rec AuthRecord) error

Put writes a record for the given server URL with file mode 0600.

type ErrReloginRequired

type ErrReloginRequired struct {
	ServerURL string
	Reason    string
}

ErrReloginRequired is returned when the stored refresh token is missing or the OAuth server rejects it. Callers surface this to the user as a prompt to re-run `klausctl auth login --remote=...`.

func (*ErrReloginRequired) Error

func (e *ErrReloginRequired) Error() string

type LoginOptions

type LoginOptions struct {
	// ClientID is the OAuth client identifier; defaults to the public
	// CIMD URL (oauth.DefaultClientIDMetadataURL).
	ClientID string
	// Scopes is the space-separated scope string to request. Defaults
	// to "openid profile email groups offline_access".
	Scopes string
	// HTTPClient is used for the token exchange; defaults to
	// http.DefaultClient when nil.
	HTTPClient *http.Client
	// BrowserOpener opens the authorize URL in the user's browser.
	// Defaults to oauth.OpenBrowser.
	BrowserOpener func(string) error
}

LoginOptions controls Login behaviour. Fields left at zero fall back to sensible defaults (CIMD URL, default scopes, http.DefaultClient).

type Target

type Target struct {
	// BaseURL is the gateway root, for example "https://gw.example.com".
	BaseURL string

	// Instance is the klaus instance name — becomes the `{instance}` path
	// segment in completions/MCP URLs.
	Instance string

	// BearerToken is attached as `Authorization: Bearer <token>` when set.
	BearerToken string

	// ChannelID (hostname) identifies the caller's machine.
	ChannelID string

	// UserID identifies the authenticated user (JWT `sub` or $USER).
	UserID string

	// ThreadID identifies the conversation/session (defaults to a stable
	// hash of the working directory when the user does not set --session).
	ThreadID string
}

Target describes a remote klaus-gateway endpoint plus the routing identities attached to every request.

func NewTarget

func NewTarget(remoteURL, instance, session, bearer string) (Target, error)

NewTarget composes a Target from a remote URL, instance name, session override (may be empty) and bearer token (may be empty). Channel ID and user ID are resolved from the host environment.

func (Target) CompletionsURL

func (t Target) CompletionsURL() string

CompletionsURL is the OpenAI-compatible chat-completions endpoint for this target: `<base>/v1/<instance>/chat/completions`.

func (Target) Headers

func (t Target) Headers() map[string]string

Headers returns the routing header map attached to every gateway call. Callers should merge this into their request headers; empty fields are omitted so the gateway can apply defaults.

func (Target) MCPURL

func (t Target) MCPURL() string

MCPURL is the streamable-HTTP MCP endpoint for this target: `<base>/v1/<instance>/mcp`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL