plugin

package
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package plugin provides the public contract for writing Restish out-of-process plugins.

Restish supports three plugin styles:

  • hook plugins for auth, middleware, loader, and formatter hooks
  • command plugins for top-level workflow commands
  • TLS signer plugins for external mTLS signing

Startup contract

Plugin binaries are discovered as executables named "restish-<name>". Restish starts them with one of these startup flags:

  • StartupFlagManifest: write a CBOR Manifest to stdout
  • StartupFlagCommands: write a CBOR command list to stdout (command plugins)

Most plugins should use HandleStartupFlags or Run instead of manually handling startup flags.

Runtime transport

All messages — startup responses and runtime messages alike — are plain CBOR data items written directly to stdin/stdout. CBOR is self-delimiting, so no length prefix or other framing is needed. Any language with a CBOR library can implement a plugin.

Use WriteMessage and ReadMessage for runtime messages. For command plugins, prefer Run and CommandClient unless you need lower-level stream control. WriteManifest and WriteCommands are convenience wrappers for startup responses.

For hook plugins that read a single message, ReadMessage(r, v) is sufficient. Command and TLS-signer plugins receive multiple messages on the same stdin, so they must create one Decoder with NewDecoder(os.Stdin) and call ReadMessage on it for every read. Discarding the Decoder between calls loses bytes that were already buffered internally.

Command-plugin messages

Command plugins should prefer the typed message structs in messages.go:

  • InitMsg for the initial host -> plugin command selection
  • HTTPRequestMsg / HTTPResponseMsg for delegated HTTP
  • APISpecMsg / APISpecResponseMsg for fetching registered API specs
  • ListAPIsMsg / ListProfilesMsg for config discovery
  • ConfigReadMsg for effective API/profile/plugin config
  • PromptMsg / ConfirmMsg for user interaction
  • ResponseMsg, StdoutDataMsg, StderrDataMsg, WarnMsg, and DoneMsg for output

For simple command plugins, plugin.Run and CommandClient are usually enough.

Hook-plugin payload shapes

Most hook plugins receive one CBOR map and, except for formatter hooks, return one CBOR reply map.

  • auth: request contains api_name, profile_name, params, and request metadata reply typically returns request.header updates
  • request-middleware: request contains the outbound request metadata reply can return updated request headers
  • response-middleware: request contains original request metadata plus normalized response fields reply may set drop, follow, or response
  • loader: request contains content_type and raw body bytes reply returns an OpenAPI document in body plus optional content_type
  • formatter: plugins receive a stream of formatter messages (`start`, `item`, `end`) on stdin and write final formatted bytes directly to stdout. For ordinary full-response renders the host usually sends `start` with the full normalized response body followed by `end`. For paginated or event-stream output the host sends `start`, then one or more `item` messages, then `end`.

See site/content/en/docs/plugins/quickstart.md for the fastest practical path to a working plugin, and docs/design/019-hook-plugins.md plus docs/design/020-command-plugins.md for the full protocol details.

Index

Constants

View Source
const (
	// CommandPluginProtocolVersion is the current command-plugin discovery
	// protocol version. A plugin that emits a larger version requires a newer
	// Restish host.
	CommandPluginProtocolVersion = 1

	// StartupFlagManifest asks a plugin to write its Manifest and exit.
	StartupFlagManifest = "--rsh-plugin-manifest"
	// StartupFlagCommands asks a command plugin to write its command list and exit.
	StartupFlagCommands = "--rsh-plugin-commands"
	// StartupFlagColor tells a command plugin whether host terminal color is enabled.
	StartupFlagColor = "--rsh-color"
	// StartupFlagStdoutTTY tells a command plugin whether host stdout is a TTY.
	StartupFlagStdoutTTY = "--rsh-stdout-tty"
	// StartupFlagStderrTTY tells a command plugin whether host stderr is a TTY.
	StartupFlagStderrTTY = "--rsh-stderr-tty"
	// StartupFlagTheme carries the host's configured terminal theme as JSON.
	StartupFlagTheme = "--rsh-theme"
)
View Source
const (
	// FeatureManifestRequiredFeatures means the host understands manifest
	// required_features validation.
	FeatureManifestRequiredFeatures = "manifest.required_features"
	// FeatureLoaderSourceMetadata means loader hooks receive content_type,
	// source_url, and local_path metadata when available.
	FeatureLoaderSourceMetadata = "loader.source_metadata"
	// FeatureRequestFinalBody means auth and request-middleware hooks may
	// receive the final request body bytes when Restish has them.
	FeatureRequestFinalBody = "request.final_body"
)
View Source
const (
	// Plugin → host requests.
	MsgTypeInit         = "init"
	MsgTypeHTTPRequest  = "http-request"
	MsgTypeAPISpec      = "api-spec"
	MsgTypeListAPIs     = "list-apis"
	MsgTypeListProfiles = "list-profiles"
	MsgTypeConfigRead   = "config-read"
	MsgTypePrompt       = "prompt"
	MsgTypeConfirm      = "confirm"
	MsgTypeResponse     = "response"
	MsgTypeDone         = "done"
	MsgTypeStdoutData   = "stdout-data"
	MsgTypeStderrData   = "stderr-data"
	MsgTypeWarn         = "warn"
	MsgTypeProgress     = "progress"
	MsgTypeSpinner      = "spinner"
	MsgTypeLog          = "log"

	// Host → plugin responses.
	MsgTypeHTTPResponse         = "http-response"
	MsgTypeAPISpecResponse      = "api-spec-response"
	MsgTypeListAPIsResponse     = "list-apis-response"
	MsgTypeListProfilesResponse = "list-profiles-response"
	MsgTypeConfigReadResponse   = "config-read-response"
	MsgTypePromptResponse       = "prompt-response"
	MsgTypeConfirmResponse      = "confirm-response"

	// Host → plugin passthrough-stdio data.
	MsgTypeStdinData  = "stdin-data"
	MsgTypeStdinClose = "stdin-close"

	// TLS signer plugin protocol.
	MsgTypeTLSSignerSign     = "sign"     // host → plugin: sign request
	MsgTypeTLSSignerReady    = "ready"    // plugin → host: ready with certificate
	MsgTypeTLSSignerShutdown = "shutdown" // host → plugin: graceful shutdown request
)

Message type constants for the command plugin protocol. Use these instead of bare strings to avoid typos; a mismatched type string causes the host or plugin to silently ignore the message.

Variables

View Source
var DecMode = func() cbor.DecMode {
	dm, err := cbor.DecOptions{
		DefaultMapType:   reflect.TypeOf(map[string]any{}),
		MaxNestedLevels:  maxCBORNestedLevels,
		MaxArrayElements: maxCBORArrayElements,
		MaxMapPairs:      maxCBORMapPairs,
	}.DecMode()
	if err != nil {
		panic("plugin: creating CBOR decode mode: " + err.Error())
	}
	return dm
}()

DecMode is a CBOR decode mode configured to use map[string]any for all CBOR maps (including nested ones), rather than the default map[any]any. It also applies the same structural limits that Restish uses for plugin messages, so buggy plugins cannot force unbounded map, array, or nesting allocations before typed validation runs.

Functions

func ArgsWithoutStartupFlags

func ArgsWithoutStartupFlags(args []string) []string

ArgsWithoutStartupFlags strips Restish-injected startup and terminal flags from the beginning of args. Flags with the same names after the first user argument are preserved as user input.

func HandleStartupFlags

func HandleStartupFlags(w io.Writer, m Manifest, cmds []CommandDecl) bool

HandleStartupFlags checks the Restish-injected startup prefix in os.Args for StartupFlagManifest or StartupFlagCommands. If either flag is found the appropriate CBOR response is written to w and the function returns true — the caller should return from main immediately.

func main() {
    if plugin.HandleStartupFlags(os.Stdout, manifest, cmds) { return }
    // ... command dispatch
}

func MessageType

func MessageType(raw []byte) string

MessageType returns the "type" field of a raw CBOR message without fully decoding it. Returns an empty string if the field is absent or the data is not valid CBOR.

func MsgBytes

func MsgBytes(v any) []byte

MsgBytes coerces a CBOR-decoded value into a []byte. CBOR byte strings decode to []byte natively. Some CBOR implementations or intermediate representations may produce a string or a []any of integers instead; this handles all three forms so callers do not need to special-case.

func MsgInt

func MsgInt(v any) int

MsgInt coerces a CBOR-decoded value into an int. CBOR integers may be decoded as int, int64, uint64, or float64 depending on the decoder configuration and value; this handles all common forms.

func MsgStrings

func MsgStrings(v any) []string

MsgStrings coerces a CBOR-decoded value into a []string. CBOR arrays of strings decode to []any; this extracts the string items.

func ReadMessage

func ReadMessage(r io.Reader, v any) error

ReadMessage reads one CBOR data item from r and unmarshals it into v (which must be a pointer). It is intended for one-shot reads such as hook plugins. For command or TLS-signer plugins that receive multiple messages, create a Decoder with NewDecoder and call ReadMessage on that instead.

func Run

func Run(m Manifest, cmds []CommandDecl, fn func(command string, args []string, client *CommandClient) error)

Run is the complete main-loop for simple command plugins. It handles startup flags, reads the init message from os.Stdin, creates a CommandClient, and calls fn with the command name, args, and client.

On success Run sends a done message with exit code 0 and returns. On error Run sends the error to stderr and exits with code 1.

func main() {
    plugin.Run(manifest, cmds, func(command string, args []string, c *plugin.CommandClient) error {
        // ... handle command
        return nil
    })
}

func WriteCommands

func WriteCommands(w io.Writer, cmds []CommandDecl) error

WriteCommands serialises cmds as a CBOR map with a "commands" array and writes it to w. It is the canonical way to respond to --rsh-plugin-commands.

case plugin.StartupFlagCommands:
    return plugin.WriteCommands(os.Stdout, cmds)

func WriteManifest

func WriteManifest(w io.Writer, m Manifest) error

WriteManifest serialises m as a CBOR data item and writes it to w. It is the canonical way to respond to --rsh-plugin-manifest.

case plugin.StartupFlagManifest:
    return plugin.WriteManifest(os.Stdout, m)

func WriteMessage

func WriteMessage(w io.Writer, v any) error

WriteMessage CBOR-encodes v and writes it to w as a single CBOR data item.

Types

type APIOperation

type APIOperation struct {
	ID                   string         `cbor:"id"`
	Method               string         `cbor:"method"`
	Path                 string         `cbor:"path"`
	Summary              string         `cbor:"summary,omitempty"`
	Description          string         `cbor:"description,omitempty"`
	Deprecated           bool           `cbor:"deprecated,omitempty"`
	Parameters           []APIParam     `cbor:"parameters,omitempty"`
	HasBody              bool           `cbor:"has_body,omitempty"`
	BodyRequired         bool           `cbor:"body_required,omitempty"`
	RequestMediaType     string         `cbor:"request_media_type,omitempty"`
	RequestSchema        map[string]any `cbor:"request_schema,omitempty"`
	RequestSchemaDialect string         `cbor:"request_schema_dialect,omitempty"`
	MCPIgnore            bool           `cbor:"mcp_ignore,omitempty"`
}

APIOperation is the host's resolved, config-aware representation of one OpenAPI HTTP operation. It mirrors the generated-command model so command plugins do not need to re-parse raw OpenAPI specs.

type APIParam

type APIParam struct {
	Name             string         `cbor:"name"`
	In               string         `cbor:"in"`
	Required         bool           `cbor:"required,omitempty"`
	Description      string         `cbor:"description,omitempty"`
	Type             string         `cbor:"type,omitempty"`
	ItemType         string         `cbor:"item_type,omitempty"`
	Style            string         `cbor:"style,omitempty"`
	Explode          *bool          `cbor:"explode,omitempty"`
	AllowReserved    bool           `cbor:"allow_reserved,omitempty"`
	ContentMediaType string         `cbor:"content_media_type,omitempty"`
	Schema           map[string]any `cbor:"schema,omitempty"`
	SchemaDialect    string         `cbor:"schema_dialect,omitempty"`
	Enum             []string       `cbor:"enum,omitempty"`
}

APIParam is a resolved operation parameter for APIOperation.

type APISpecMsg

type APISpecMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	Name      string `cbor:"name"`
	Profile   string `cbor:"profile,omitempty"`
}

APISpecMsg asks the host to load the OpenAPI spec for a registered API.

type APISpecResponseMsg

type APISpecResponseMsg struct {
	Type        string         `cbor:"type"`
	RequestID   string         `cbor:"request_id,omitempty"`
	Name        string         `cbor:"name"`
	Profile     string         `cbor:"profile,omitempty"`
	ContentType string         `cbor:"content_type,omitempty"`
	Raw         []byte         `cbor:"raw,omitempty"`
	Operations  []APIOperation `cbor:"operations,omitempty"`
	Error       string         `cbor:"error,omitempty"`
}

APISpecResponseMsg is the host reply to an APISpecMsg.

type AuthHookInput

type AuthHookInput struct {
	Type    string            `cbor:"type" json:"type"`
	API     string            `cbor:"api" json:"api"`
	Profile string            `cbor:"profile" json:"profile"`
	Params  map[string]string `cbor:"params" json:"params"`
	Request HookRequest       `cbor:"request" json:"request"`
}

AuthHookInput is sent to plugins registered for the "auth" hook.

type AuthHookOutput

type AuthHookOutput struct {
	Request *HookRequestHeaderUpdate `cbor:"request,omitempty" json:"request,omitempty"`
}

AuthHookOutput is the reply from an "auth" hook plugin.

type CommandClient

type CommandClient struct {

	// StdinDataHandler is called with each chunk of stdin data received from
	// the host while Do() is waiting for an http-response. Set this before
	// calling Do() when passthrough_stdio is active.
	StdinDataHandler func(data []byte)

	// StdinCloseHandler is called when the host signals that stdin has reached
	// EOF while Do() is waiting for an http-response.
	StdinCloseHandler func()
	// contains filtered or unexported fields
}

CommandClient is the plugin-side counterpart of the host command-plugin runner. It wraps the host stdin/stdout pair and provides helpers for making authenticated HTTP calls, writing output, and signalling completion.

Most command plugins should create one with NewCommandClient and use it for all communication with the host.

Plugins that declare passthrough_stdio should register StdinDataHandler and StdinCloseHandler before calling Do(). These handlers are invoked for any stdin-data or stdin-close frames that arrive after Do starts the background response reader.

func NewCommandClient

func NewCommandClient(in io.Reader, out io.Writer) *CommandClient

NewCommandClient returns a CommandClient backed by the given reader/writer. Pass os.Stdin and os.Stdout from a plugin's main function. A single Decoder is created from in and reused for all reads. Call ReadMessage for startup messages before calling Do; after Do starts the background response reader, all host replies are routed through Do.

func NewCommandClientFromDecoder

func NewCommandClientFromDecoder(dec *Decoder, out io.Writer) *CommandClient

NewCommandClientFromDecoder returns a CommandClient that continues reading from an existing decoder. Use this when startup code has already consumed initial messages from the same input stream.

func (*CommandClient) ConfigRead

func (c *CommandClient) ConfigRead(api, profile, pluginName string) (*ConfigReadResponseMsg, error)

ConfigRead asks the host for API/profile config and/or plugin config.

func (*CommandClient) ConfigReadContext

func (c *CommandClient) ConfigReadContext(ctx context.Context, api, profile, pluginName string) (*ConfigReadResponseMsg, error)

ConfigReadContext asks the host for API/profile config and/or plugin config, returning when ctx is canceled if the host does not reply.

func (*CommandClient) Confirm

func (c *CommandClient) Confirm(message string) (*ConfirmResponseMsg, error)

Confirm asks the host to display message and read a yes/no value.

func (*CommandClient) ConfirmContext

func (c *CommandClient) ConfirmContext(ctx context.Context, message string) (*ConfirmResponseMsg, error)

ConfirmContext asks the host to display message and read a yes/no value, returning when ctx is canceled if the host does not reply.

func (*CommandClient) Do

Do sends one HTTP request to the host and blocks until the matching http-response arrives. While waiting, any stdin-data or stdin-close frames are dispatched to StdinDataHandler / StdinCloseHandler if registered.

Do is safe to call concurrently. Requests without RequestID are assigned one automatically so replies can be routed back to the caller.

func (*CommandClient) Done

func (c *CommandClient) Done(exitCode int) error

Done signals that the plugin has finished. exitCode 0 means success; any other value causes the host to exit with that code.

func (*CommandClient) FetchAPISpec

func (c *CommandClient) FetchAPISpec(name string) (*APISpecResponseMsg, error)

FetchAPISpec asks the host to load the OpenAPI spec or resolved operation metadata for a registered API name.

func (*CommandClient) FetchAPISpecContext

func (c *CommandClient) FetchAPISpecContext(ctx context.Context, name, profile string) (*APISpecResponseMsg, error)

FetchAPISpecContext asks the host to load OpenAPI metadata for a registered API name and optional profile, returning when ctx is canceled if the host does not reply.

func (*CommandClient) ListAPIs

func (c *CommandClient) ListAPIs() (*ListAPIsResponseMsg, error)

ListAPIs asks the host for configured API names.

func (*CommandClient) ListAPIsContext

func (c *CommandClient) ListAPIsContext(ctx context.Context) (*ListAPIsResponseMsg, error)

ListAPIsContext asks the host for configured API names, returning when ctx is canceled if the host does not reply.

func (*CommandClient) ListProfiles

func (c *CommandClient) ListProfiles(api string) (*ListProfilesResponseMsg, error)

ListProfiles asks the host for profile names under api.

func (*CommandClient) ListProfilesContext

func (c *CommandClient) ListProfilesContext(ctx context.Context, api string) (*ListProfilesResponseMsg, error)

ListProfilesContext asks the host for profile names under api, returning when ctx is canceled if the host does not reply.

func (*CommandClient) Progress

func (c *CommandClient) Progress(text string) error

Progress sends an informational progress message to the host.

func (*CommandClient) Prompt

func (c *CommandClient) Prompt(message string, hidden bool) (*PromptResponseMsg, error)

Prompt asks the host to display message and read a value from the user.

func (*CommandClient) PromptContext

func (c *CommandClient) PromptContext(ctx context.Context, message string, hidden bool) (*PromptResponseMsg, error)

PromptContext asks the host to display message and read a value from the user, returning when ctx is canceled if the host does not reply.

func (*CommandClient) ReadMessage

func (c *CommandClient) ReadMessage(v any) error

ReadMessage reads one CBOR message from the host into v. Use this when the plugin needs to receive startup messages that are not covered by Do.

func (*CommandClient) Response

func (c *CommandClient) Response(status int, headers map[string][]string, body any) error

Response asks the host to format and display response data using the same output machinery as regular Restish responses.

func (*CommandClient) StderrWriter

func (c *CommandClient) StderrWriter() io.Writer

StderrWriter returns an io.Writer that routes writes through WriteStderr.

func (*CommandClient) StdoutWriter

func (c *CommandClient) StdoutWriter() io.Writer

StdoutWriter returns an io.Writer that routes writes through WriteStdout.

func (*CommandClient) Warn

func (c *CommandClient) Warn(text string) error

Warn sends a warning message to the host, which displays it to the user through whatever UI mechanism it uses.

func (*CommandClient) WriteMessage

func (c *CommandClient) WriteMessage(v any) error

WriteMessage serialises v as a CBOR data item and sends it to the host. It is safe to call from multiple goroutines.

func (*CommandClient) WriteStderr

func (c *CommandClient) WriteStderr(data []byte) error

WriteStderr writes data to the user's terminal stderr via the host.

func (*CommandClient) WriteStdout

func (c *CommandClient) WriteStdout(data []byte) error

WriteStdout writes data to the user's terminal via the host.

type CommandDecl

type CommandDecl struct {
	// Name is the top-level command name contributed by the plugin.
	Name string `cbor:"name" json:"name"`
	// Short is the one-line help text shown in command listings.
	Short string `cbor:"short,omitempty" json:"short,omitempty"`
	// Long is optional extended help text.
	Long string `cbor:"long,omitempty" json:"long,omitempty"`
	// PassthroughStdio asks the host to forward stdin frames to the plugin.
	PassthroughStdio bool `cbor:"passthrough_stdio,omitempty" json:"passthrough_stdio,omitempty"`
}

CommandDecl describes one command that a command-plugin exposes. It is used in the response to --rsh-plugin-commands.

type CommandDiscoveryResponse

type CommandDiscoveryResponse struct {
	ProtocolVersion int           `cbor:"protocol_version,omitempty" json:"protocol_version,omitempty"`
	Commands        []CommandDecl `cbor:"commands" json:"commands"`
}

CommandDiscoveryResponse is the response to StartupFlagCommands.

type ConfigReadMsg

type ConfigReadMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	API       string `cbor:"api,omitempty"`
	Profile   string `cbor:"profile,omitempty"`
	// Plugin is the plugin's short name (without the "restish-" prefix).
	// When set, the response includes PluginConfig populated from
	// restish.json's plugins[Plugin] entry.
	Plugin string `cbor:"plugin,omitempty"`
}

ConfigReadMsg asks the host for the effective configuration of an API profile (base URL, persistent headers and query params), and/or the plugin-specific config stored under plugins[Plugin] in restish.json.

type ConfigReadResponseMsg

type ConfigReadResponseMsg struct {
	Type      string   `cbor:"type"`
	RequestID string   `cbor:"request_id,omitempty"`
	BaseURL   string   `cbor:"base_url,omitempty"`
	Headers   []string `cbor:"headers,omitempty"`
	Query     []string `cbor:"query,omitempty"`
	Error     string   `cbor:"error,omitempty"`
	// PluginConfig holds the parsed plugins[name] entry from restish.json,
	// or nil when no config is stored for this plugin.
	PluginConfig any `cbor:"plugin_config,omitempty"`
}

ConfigReadResponseMsg is the host reply to a ConfigReadMsg. Auth secrets are intentionally excluded.

type ConfirmMsg

type ConfirmMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	Message   string `cbor:"message"`
}

ConfirmMsg asks the host to display a message and read a yes/no answer.

type ConfirmResponseMsg

type ConfirmResponseMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	Value     bool   `cbor:"value"`
	Error     string `cbor:"error,omitempty"`
}

ConfirmResponseMsg is the host reply to a ConfirmMsg.

type Decoder

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

Decoder reads sequential CBOR messages from a stream. It maintains an internal read buffer, so a single Decoder instance must be reused for all reads from the same underlying reader — discarding it between calls would lose bytes that were already buffered.

Use NewDecoder for any reader from which multiple messages will be read (os.Stdin in a command or TLS-signer plugin). Hook plugins that receive exactly one message may use the package-level ReadMessage instead.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a Decoder that reads from r.

Reuse a single Decoder for the lifetime of the stream. Constructing a new Decoder inside a read loop can discard bytes that were already buffered and silently lose messages.

func (*Decoder) ReadMessage

func (d *Decoder) ReadMessage(v any) error

ReadMessage reads one CBOR data item and unmarshals it into v (which must be a pointer).

func (*Decoder) ReadRaw

func (d *Decoder) ReadRaw() ([]byte, error)

ReadRaw reads the next CBOR data item from the stream and returns it as raw bytes. The caller can inspect the bytes (e.g. with MessageType) and then decode into a specific typed struct using DecMode.Unmarshal.

type DoneMsg

type DoneMsg struct {
	Type     string `cbor:"type"`
	ExitCode int    `cbor:"exit_code,omitempty"`
}

DoneMsg signals that the plugin has finished. ExitCode 0 is success.

type FollowRequest

type FollowRequest struct {
	Method      string            `cbor:"method,omitempty" json:"method,omitempty"`
	URI         string            `cbor:"uri" json:"uri"`
	Headers     map[string]string `cbor:"headers,omitempty" json:"headers,omitempty"`
	Body        any               `cbor:"body,omitempty" json:"body,omitempty"`
	ContentType string            `cbor:"content_type,omitempty" json:"content_type,omitempty"`
}

FollowRequest instructs the host to issue a follow-up HTTP request.

type FormatterRequest

type FormatterRequest struct {
	Type     string            `cbor:"type" json:"type"`
	Format   string            `cbor:"format" json:"format"`
	Color    bool              `cbor:"color,omitempty" json:"color,omitempty"`
	Event    string            `cbor:"event" json:"event"`
	Response FormatterResponse `cbor:"response" json:"response"`
}

FormatterRequest is sent to formatter plugins. Type is always "formatter" and Event is one of "start", "item", or "end".

type FormatterResponse

type FormatterResponse struct {
	Proto   string              `cbor:"proto,omitempty" json:"proto,omitempty"`
	Status  int                 `cbor:"status,omitempty" json:"status,omitempty"`
	Headers map[string][]string `cbor:"headers,omitempty" json:"headers,omitempty"`
	Links   map[string]any      `cbor:"links,omitempty" json:"links,omitempty"`
	Body    any                 `cbor:"body,omitempty" json:"body,omitempty"`
}

FormatterResponse is the normalized response shape forwarded to formatter plugins. The host may include the full response body on "start" for a normal one-shot render, or send body values incrementally on subsequent "item" messages for paginated and event-stream output.

type HTTPRequestMsg

type HTTPRequestMsg struct {
	Type        string            `cbor:"type"`
	RequestID   string            `cbor:"request_id,omitempty"`
	Method      string            `cbor:"method,omitempty"`
	URI         string            `cbor:"uri"`
	Headers     map[string]string `cbor:"headers,omitempty"`
	Body        any               `cbor:"body,omitempty"`
	ContentType string            `cbor:"content_type,omitempty"`
	// NoCache bypasses the response cache for this request.
	NoCache bool `cbor:"no_cache,omitempty"`
	// CacheTTL (seconds) injects Cache-Control: max-age=N on the request.
	// Only entries fresher than this TTL are served from the cache.
	CacheTTL int `cbor:"cache_ttl,omitempty"`
	// Timeout (seconds) sets a per-request deadline. 0 means no deadline.
	Timeout int `cbor:"timeout,omitempty"`
	// Filter is an optional shorthand or jq expression. When set, the host
	// applies it to the full response document before sending it back.
	Filter string `cbor:"filter,omitempty"`
}

HTTPRequestMsg asks the host to perform an HTTP request on behalf of the plugin and reply with an HTTPResponseMsg.

type HTTPResponseMsg

type HTTPResponseMsg struct {
	Type      string              `cbor:"type"`
	RequestID string              `cbor:"request_id,omitempty"`
	Status    int                 `cbor:"status"`
	Headers   map[string][]string `cbor:"headers,omitempty"`
	URL       string              `cbor:"url,omitempty"`
	Links     map[string]any      `cbor:"links,omitempty"`
	Body      any                 `cbor:"body"`
	// Error is set when the HTTP request itself failed.
	Error string `cbor:"error,omitempty"`
}

HTTPResponseMsg is the host reply to an HTTPRequestMsg.

type HookRequest

type HookRequest struct {
	Method     string              `cbor:"method" json:"method"`
	URI        string              `cbor:"uri" json:"uri"`
	Headers    map[string][]string `cbor:"headers" json:"headers"`
	Body       []byte              `cbor:"body,omitempty" json:"body,omitempty"`
	BodySHA256 string              `cbor:"body_sha256,omitempty" json:"body_sha256,omitempty"`
}

HookRequest carries the current HTTP request state forwarded to hook plugins.

type HookRequestHeaderUpdate

type HookRequestHeaderUpdate struct {
	// Each value is either a string or []string.
	Headers map[string]any `cbor:"headers,omitempty" json:"headers,omitempty"`
}

HookRequestHeaderUpdate holds headers that a hook plugin wants to set or replace on the outgoing request. Only headers are applied; method and URI fields are intentionally absent because the request has already been prepared.

type HookResponse

type HookResponse struct {
	Status  int                 `cbor:"status" json:"status"`
	Headers map[string][]string `cbor:"headers" json:"headers"`
	Body    any                 `cbor:"body" json:"body"`
}

HookResponse carries the current HTTP response state forwarded to hook plugins.

type HookResponseUpdate

type HookResponseUpdate struct {
	Body any `cbor:"body,omitempty" json:"body,omitempty"`
	// Each value is either a string or []string.
	Headers map[string]any `cbor:"headers,omitempty" json:"headers,omitempty"`
}

HookResponseUpdate carries partial response modifications from a "response-middleware" plugin.

type InitMsg

type InitMsg struct {
	Type    string   `cbor:"type"`
	Command string   `cbor:"command"`
	Args    []string `cbor:"args"`
}

InitMsg is the first message sent from the host to the plugin after startup. It carries the sub-command name and the raw CLI arguments.

type ListAPIsMsg

type ListAPIsMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
}

ListAPIsMsg asks the host for the list of configured API names.

type ListAPIsResponseMsg

type ListAPIsResponseMsg struct {
	Type      string   `cbor:"type"`
	RequestID string   `cbor:"request_id,omitempty"`
	APIs      []string `cbor:"apis"`
	Error     string   `cbor:"error,omitempty"`
}

ListAPIsResponseMsg is the host reply to a ListAPIsMsg.

type ListProfilesMsg

type ListProfilesMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	API       string `cbor:"api"`
}

ListProfilesMsg asks the host for the profile names of a specific API.

type ListProfilesResponseMsg

type ListProfilesResponseMsg struct {
	Type      string   `cbor:"type"`
	RequestID string   `cbor:"request_id,omitempty"`
	API       string   `cbor:"api"`
	Profiles  []string `cbor:"profiles"`
	Error     string   `cbor:"error,omitempty"`
}

ListProfilesResponseMsg is the host reply to a ListProfilesMsg.

type LoaderRequest

type LoaderRequest struct {
	Type        string `cbor:"type" json:"type"`
	Body        []byte `cbor:"body" json:"body"`
	ContentType string `cbor:"content_type,omitempty" json:"content_type,omitempty"`
	SourceURL   string `cbor:"source_url,omitempty" json:"source_url,omitempty"`
	LocalPath   string `cbor:"local_path,omitempty" json:"local_path,omitempty"`
}

LoaderRequest is sent to plugins registered for the "loader" hook. Body contains the source document bytes. ContentType, SourceURL, and LocalPath are metadata from discovery or cache when the host has it.

type LoaderResponse

type LoaderResponse struct {
	// Body is an OpenAPI document as []byte or string.
	Body        any    `cbor:"body" json:"body"`
	ContentType string `cbor:"content_type,omitempty" json:"content_type,omitempty"`
}

LoaderResponse is returned by a "loader" hook plugin. Body must contain an OpenAPI document in JSON or YAML form. ContentType may describe that returned body when it differs from the input document's content type.

type LogMsg

type LogMsg struct {
	Type string `cbor:"type"`
	Text string `cbor:"text"`
}

LogMsg prints an informational log line on the host stderr.

type Manifest

type Manifest struct {
	// Name is the stable plugin identifier, without the "restish-" executable prefix.
	Name string `cbor:"name" json:"name"`
	// Version is a plugin-defined version string shown in plugin listings.
	Version string `cbor:"version,omitempty" json:"version,omitempty"`
	// Description is a short human-readable summary of the plugin.
	Description string `cbor:"description,omitempty" json:"description,omitempty"`
	// RestishAPIVersion is the minimum host/plugin protocol version required by
	// this plugin. Restish treats future protocol versions as backward
	// compatible unless RequiredFeatures asks for unsupported behavior.
	RestishAPIVersion int `cbor:"restish_api_version" json:"restish_api_version"`
	// Hooks lists plugin capabilities such as "command", "formatter", or "auth".
	Hooks []string `cbor:"hooks,omitempty" json:"hooks,omitempty"`
	// RequiredFeatures lists additive protocol features that must be supported
	// by the host before this plugin may run. Unknown optional manifest fields
	// are ignored, but unknown required features fail manifest loading.
	RequiredFeatures []string `cbor:"required_features,omitempty" json:"required_features,omitempty"`
	// FormatterNames lists the output format names this plugin registers when
	// the "formatter" hook is declared.
	FormatterNames []string `cbor:"formatter_names,omitempty" json:"formatter_names,omitempty"`
	// LoaderContentTypes lists the MIME types this plugin handles when the
	// "loader" hook is declared.
	LoaderContentTypes []string `cbor:"loader_content_types,omitempty" json:"loader_content_types,omitempty"`
	// AuthAPINames, when non-empty, restricts the "auth" hook to the listed
	// API names so the plugin is not invoked for every unrelated API.
	AuthAPINames []string `cbor:"auth_api_names,omitempty" json:"auth_api_names,omitempty"`
	// NeedsAuthSecrets, when true, tells Restish to forward secret auth
	// params (passwords, client secrets) and credential-bearing request headers
	// to this plugin. When false (the default), secret params are omitted and
	// Authorization, Cookie, and Proxy-Authorization request headers are sent
	// as "<redacted>" in auth and middleware hook payloads.
	NeedsAuthSecrets bool `cbor:"needs_auth_secrets,omitempty" json:"needs_auth_secrets,omitempty"`
	// HookTimeouts overrides the per-hook subprocess deadline. Keys are hook
	// names (e.g. "auth", "request-middleware"). The default is 30 s for all
	// hooks except "auth", which defaults to 5 minutes.
	HookTimeouts map[string]time.Duration `cbor:"hook_timeouts,omitempty" json:"hook_timeouts,omitempty"`
}

Manifest is the metadata a plugin reports when called with --rsh-plugin-manifest. Plugin authors populate and write this with WriteManifest instead of manually marshalling CBOR.

type ProgressMsg

type ProgressMsg struct {
	Type string `cbor:"type"`
	Text string `cbor:"text"`
}

ProgressMsg prints an informational progress line on the host stderr.

type PromptMsg

type PromptMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	Message   string `cbor:"message"`
	Hidden    bool   `cbor:"hidden,omitempty"`
}

PromptMsg asks the host to display a message and read one line from the user. When Hidden is true and stdin is a TTY, echo is suppressed (suitable for password entry).

type PromptResponseMsg

type PromptResponseMsg struct {
	Type      string `cbor:"type"`
	RequestID string `cbor:"request_id,omitempty"`
	Value     string `cbor:"value,omitempty"`
	Error     string `cbor:"error,omitempty"`
}

PromptResponseMsg is the host reply to a PromptMsg.

type RequestMiddlewareInput

type RequestMiddlewareInput struct {
	Type    string      `cbor:"type" json:"type"`
	Request HookRequest `cbor:"request" json:"request"`
}

RequestMiddlewareInput is sent to plugins registered for the "request-middleware" hook.

type RequestMiddlewareOutput

type RequestMiddlewareOutput struct {
	Request *HookRequestHeaderUpdate `cbor:"request,omitempty" json:"request,omitempty"`
}

RequestMiddlewareOutput is the reply from a "request-middleware" hook plugin.

type ResponseMiddlewareInput

type ResponseMiddlewareInput struct {
	Type     string       `cbor:"type" json:"type"`
	Request  HookRequest  `cbor:"request" json:"request"`
	Response HookResponse `cbor:"response" json:"response"`
}

ResponseMiddlewareInput is sent to plugins registered for the "response-middleware" hook.

type ResponseMiddlewareOutput

type ResponseMiddlewareOutput struct {
	Drop     bool                `cbor:"drop,omitempty" json:"drop,omitempty"`
	Follow   *FollowRequest      `cbor:"follow,omitempty" json:"follow,omitempty"`
	Response *HookResponseUpdate `cbor:"response,omitempty" json:"response,omitempty"`
}

ResponseMiddlewareOutput is the reply from a "response-middleware" hook plugin.

type ResponseMsg

type ResponseMsg struct {
	Type    string              `cbor:"type"`
	Status  int                 `cbor:"status,omitempty"`
	Headers map[string][]string `cbor:"headers,omitempty"`
	Body    any                 `cbor:"body,omitempty"`
}

ResponseMsg asks the host to format and display a response using the configured output formatter (same as a regular API response).

type SpinnerMsg

type SpinnerMsg struct {
	Type string `cbor:"type"`
	Text string `cbor:"text"`
}

SpinnerMsg requests spinner-style status text on the host stderr.

type StderrDataMsg

type StderrDataMsg struct {
	Type string `cbor:"type"`
	Data []byte `cbor:"data"`
}

StderrDataMsg sends a chunk of raw bytes to the host's stderr.

type StdinCloseMsg

type StdinCloseMsg struct {
	Type string `cbor:"type"`
}

StdinCloseMsg signals that the host's stdin has reached EOF.

type StdinDataMsg

type StdinDataMsg struct {
	Type string `cbor:"type"`
	Data []byte `cbor:"data"`
}

StdinDataMsg carries a chunk of stdin bytes from the host to the plugin (passthrough_stdio mode).

type StdoutDataMsg

type StdoutDataMsg struct {
	Type string `cbor:"type"`
	Data []byte `cbor:"data"`
}

StdoutDataMsg sends a chunk of raw bytes to the host's stdout.

type TLSSignerInitMsg

type TLSSignerInitMsg struct {
	Type   string            `cbor:"type"`
	Params map[string]string `cbor:"params"`
}

TLSSignerInitMsg is sent by the host to a tls-signer plugin at startup. The Type field is MsgTypeInit ("init").

type TLSSignerReadyMsg

type TLSSignerReadyMsg struct {
	Type        string `cbor:"type"`
	Certificate []byte `cbor:"certificate"`
}

TLSSignerReadyMsg is sent by the plugin when it has loaded its certificate and is ready to sign. Type is MsgTypeTLSSignerReady ("ready").

type TLSSignerShutdownMsg

type TLSSignerShutdownMsg struct {
	Type string `cbor:"type"`
}

TLSSignerShutdownMsg asks the plugin to release resources and exit.

type TLSSignerSignMsg

type TLSSignerSignMsg struct {
	Type   string `cbor:"type"`
	Digest []byte `cbor:"digest"`
	// Hash is the crypto.Hash value cast to uint64. 0 means no specific hash.
	Hash       uint64 `cbor:"hash,omitempty"`
	Padding    string `cbor:"padding,omitempty"`
	SaltLength int    `cbor:"salt_length,omitempty"`
}

TLSSignerSignMsg is sent by the host to request a signature. Type is MsgTypeTLSSignerSign ("sign").

type TLSSignerSignedMsg

type TLSSignerSignedMsg struct {
	Signature []byte `cbor:"signature,omitempty"`
	Error     string `cbor:"error,omitempty"`
}

TLSSignerSignedMsg is the plugin's reply to a TLSSignerSignMsg. It carries either a Signature or an Error, never both. This message has no Type field.

type TerminalContext

type TerminalContext struct {
	// Color is true when the host terminal supports ANSI colour sequences.
	Color bool
	// StdoutTTY is true when the host's stdout is connected to a terminal.
	StdoutTTY bool
	// StderrTTY is true when the host's stderr is connected to a terminal.
	StderrTTY bool
	// Theme is the host's configured Restish terminal theme entries.
	Theme map[string]string
}

TerminalContext carries terminal capability flags that the Restish host passes to command plugins as CLI arguments. Plugins that care about colour or TTY detection should call TerminalContextFromArgs(os.Args[1:]).

func TerminalContextFromArgs

func TerminalContextFromArgs(args []string) TerminalContext

TerminalContextFromArgs parses the Restish-injected terminal flags from the given argument slice (typically os.Args[1:]) and returns a TerminalContext. Unrecognised arguments are silently ignored.

ctx := plugin.TerminalContextFromArgs(os.Args[1:])

type WarnMsg

type WarnMsg struct {
	Type string `cbor:"type"`
	Text string `cbor:"text"`
}

WarnMsg prints a warning line (prefixed with "warning: ") on the host's stderr.

Jump to

Keyboard shortcuts

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