ui

package
v0.3.5 Latest Latest
Warning

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

Go to latest
Published: Jun 13, 2026 License: MIT Imports: 106 Imported by: 0

Documentation

Overview

Package ui implements the bubbletea TUI, SSH helpers, and CUE recipe execution for honey.

Index

Constants

View Source
const (
	StageFallbackDetect        = "fallback_detect"
	StageFallbackDetectFailed  = "fallback_detect_failed"
	StagePresignPutStart       = "presign_put_start"
	StagePresignPut            = "presign_put"
	StagePresignPutFailed      = "presign_put_failed"
	StagePresignGetStart       = "presign_get_start"
	StagePresignGet            = "presign_get"
	StagePresignGetFailed      = "presign_get_failed"
	StagePresignMultipartStart = "presign_multipart_start"
	StagePresignMultipart      = "presign_multipart"
	StagePresignMultipartAbort = "presign_multipart_aborted"
	StagePresignComplete       = "presign_complete"
	StagePresignCompleteFailed = "presign_complete_failed"
	StagePresignCleanup        = "presign_cleanup"
	StagePresignCleanupFailed  = "presign_cleanup_failed"
	StagePresignFallback       = "presign_falling_back_to_agent"
)

Fallback-path stage names. Emitted as the Stage field on AgentTransferEvent

Variables

This section is empty.

Functions

func BuildCueRecipeTranscript added in v0.2.8

func BuildCueRecipeTranscript(history [][]HostExecResult) string

BuildCueRecipeTranscript formats prior CUE step HostExecResult groups for an AI summarizer.

func CanTrueNASTunnel added in v0.3.0

func CanTrueNASTunnel(r hosts.Record) bool

CanTrueNASTunnel reports whether the Tunnel action can run for this TrueNAS row.

func CueHookNotifyRemote added in v0.2.8

func CueHookNotifyRemote(ctx context.Context, recipe cuetry.Recipe, stepNo int, kind string, phase, hostName string, notify *cuetry.RecipeNotify, body string)

CueHookNotifyRemote sends notify after a per-host hook; failures are logged only.

func CueStepNotifyAppendSuffix added in v0.2.8

func CueStepNotifyAppendSuffix(ctx context.Context, recipe cuetry.Recipe, stepNo int, kind string, notify *cuetry.RecipeNotify, body string) string

CueStepNotifyAppendSuffix sends notify after a successful AI step; returns text to append on missing receivers or send errors.

func CueStepNotifyRemote added in v0.2.8

func CueStepNotifyRemote(ctx context.Context, recipe cuetry.Recipe, stepNo int, kind string, notify *cuetry.RecipeNotify, body string)

CueStepNotifyRemote sends notify after a non-AI step; failures are logged only (no change to streamed host rows).

func DefaultLocalFilesRoot added in v0.2.8

func DefaultLocalFilesRoot() string

DefaultLocalFilesRoot returns the configured or home-directory root for local file browser paths.

func DetectTransferTargetRuntime added in v0.2.8

func DetectTransferTargetRuntime(cache *ClientCache, sshUser string, rec hosts.Record) (string, string, string, error)

DetectTransferTargetRuntime runs uname on the host to determine GOOS/GOARCH for agent binaries.

func DialDockerCheck added in v0.3.0

func DialDockerCheck(user string, r hosts.Record, reg hostexec.Registry) error

DialDockerCheck verifies that a docker record can reach the Engine API (dial + close). Re-exported from dockerprovider for callers that already import ui.

func DialSSHLeafForRecord added in v0.2.7

func DialSSHLeafForRecord(user string, r hosts.Record) (*ssh.Client, func(), error)

DialSSHLeafForRecord returns a leaf *ssh.Client for SSH to hosts.Record.PrimaryIP (same transport as the TUI). Kubernetes pod records are not supported for raw SSH in this helper.

func DialTrueNASUpstream added in v0.3.1

func DialTrueNASUpstream(ctx context.Context, _ string, r hosts.Record, address string) (net.Conn, error)

DialTrueNASUpstream provides an in-memory net.Conn proxied over the API shell.

func DockerInteractiveRunner added in v0.3.4

func DockerInteractiveRunner() dockerprovider.InteractiveRunner

DockerInteractiveRunner returns the ui-backed docker interactive session runner.

func FormatCueStepHostResultsForNotify added in v0.2.8

func FormatCueStepHostResultsForNotify(stepNo int, group []HostExecResult) string

FormatCueStepHostResultsForNotify formats one step’s host results for notify bodies (non-AI steps).

func FormatTargetForDryRun

func FormatTargetForDryRun(r hosts.Record) string

FormatTargetForDryRun returns a string describing how the target will be connected to.

func HostConnectableForTransfer added in v0.2.8

func HostConnectableForTransfer(r hosts.Record) bool

HostConnectableForTransfer reports whether a record can be dialed for SSH, k8s exec, or docker exec.

func HostsForRecipeMeta added in v0.3.0

func HostsForRecipeMeta(jobs []hosts.Record, limit int) []hosts.Record

HostsForRecipeMeta copies up to limit connectable host records for recipe-meta (web re-run).

func IsAgentTransferValidationError added in v0.2.8

func IsAgentTransferValidationError(err error) bool

IsAgentTransferValidationError reports whether err is an AgentTransferValidationError (HTTP 400 class input).

func IsSSHConnTransientError added in v0.2.8

func IsSSHConnTransientError(err error) bool

IsSSHConnTransientError reports whether err is a transport-level failure that often clears after closing the TCP/SSH session and dialing again (stale cache entry, local routing/socket glitch, reset by peer).

func K8sInteractiveRunner added in v0.3.4

func K8sInteractiveRunner() k8sprovider.InteractiveRunner

K8sInteractiveRunner returns the ui-backed k8s interactive session runner.

func LoadAISystemPromptFromConfigPath added in v0.2.8

func LoadAISystemPromptFromConfigPath(configPath string) string

LoadAISystemPromptFromConfigPath returns defaults.ai_system_prompt from the honey YAML at path, if loadable.

func LoadTransferConfigFromConfigPath added in v0.2.8

func LoadTransferConfigFromConfigPath(configPath string) config.TransferConfigEffective

LoadTransferConfigFromConfigPath returns the effective transfer config from the honey YAML at path. If path is empty or the file fails to load, returns defaults.

func NewPostgresBridge added in v0.3.4

func NewPostgresBridge(h *plugins.HostRunContext, pools *postgres.PoolManager) plugins.PostgresBridge

NewPostgresBridge returns a PostgresBridge for one plugin host invocation.

func NewRemoteBridge added in v0.3.4

func NewRemoteBridge(user string, record hosts.Record, cache *ClientCache, reg hostexec.Registry, recipeDir, runAs string, env map[string]string, allowedPaths map[string]string) plugins.RemoteBridge

NewRemoteBridge returns a RemoteBridge for one plugin host invocation.

func PrintStaticTable added in v0.2.6

func PrintStaticTable(records []hosts.Record) error

PrintStaticTable prints the records as an ASCII table to stdout and exits.

func RemoteCopyLocalToRemote added in v0.2.8

func RemoteCopyLocalToRemote(user string, record hosts.Record, localPath, remotePath string, cache *ClientCache) error

RemoteCopyLocalToRemote uploads a local file to the remote path.

func RemoteCopyRemoteToLocal added in v0.2.8

func RemoteCopyRemoteToLocal(user string, record hosts.Record, remotePath, localPath string, cache *ClientCache) error

RemoteCopyRemoteToLocal downloads a remote file to a local path.

func ResizeFromColsRows added in v0.2.7

func ResizeFromColsRows(cols, rows int) *remotecommand.TerminalSize

ResizeFromColsRows returns a terminal size for k8s remotecommand, or nil if cols or rows are non-positive.

func ResolveAgentTransferSigningHints added in v0.2.8

func ResolveAgentTransferSigningHints(configPath string, cloud AgentCloudBackend, ref *CloudBackendRef) (cloudtransfer.SigningHints, error)

ResolveAgentTransferSigningHints loads honey config when ref is set and fills AWS/GCP signing hints (same semantics as the web files API). configPath is the explicit or resolved honey YAML path.

func ResolveAppDialer added in v0.3.1

func ResolveAppDialer(_ context.Context, user string, rec hosts.Record, _ string) (proxy.Dialer, io.Closer, error)

ResolveAppDialer returns the correct proxy.Dialer and an optional io.Closer for any hosts.Record. It hides all provider-specific connection logic (SSH, K8s exec, TrueNAS shell API, etc.).

func ResolveAppDialerWithCache added in v0.3.1

func ResolveAppDialerWithCache(user string, rec hosts.Record, cache *ClientCache) (proxy.Dialer, io.Closer, error)

ResolveAppDialerWithCache returns an app proxy dialer, borrowing SSH clients from cache when available.

func ResolveLocalPathUnderRoot added in v0.2.8

func ResolveLocalPathUnderRoot(root, requested string) (string, error)

ResolveLocalPathUnderRoot resolves requested against root and ensures the result stays under root.

func RewritePluginConfigTunnelStep added in v0.3.0

func RewritePluginConfigTunnelStep(config []byte, pluginID string, tunnelCoord *RecipeTunnelCoordinator, sshUser string, target hosts.Record, execute bool) ([]byte, error)

RewritePluginConfigTunnelStep sets base_url from a recipe tunnel step endpoint. When pluginID is rclone, tunnel_step or a non-empty base_url is required on execute.

func RunCueRecipeSteps

func RunCueRecipeSteps(ctx context.Context, out io.Writer, p CueRecipeRunParams, rec *SessionRecorder) (runErr error)

RunCueRecipeSteps executes a CUE recipe over a slice of target records without streaming. cliEnv is merged into each command/script step's remote env (overrides recipe env on duplicate keys); nil is treated as empty. configPath is the resolved honey YAML path (may be empty); agent_transfer with cloud_backend_ref requires it. rec, when non-nil, records a batch .hrec.jsonl (plan on dry-run, result rows on execute). Caller must Close(rec).

func RunDockerWebTTY added in v0.3.0

func RunDockerWebTTY(
	ctx context.Context,
	user string,
	r hosts.Record,
	stdin io.Reader,
	stdout io.Writer,
	cols, rows int,
	resizeCh <-chan DockerTerminalSize,
	reg hostexec.Registry,
) error

RunDockerWebTTY runs an interactive shell in a container with TTY over stdin/stdout.

func RunK8sPodWebTTY added in v0.2.7

func RunK8sPodWebTTY(
	ctx context.Context,
	r hosts.Record,
	stdin io.Reader,
	stdout, stderr io.Writer,
	cols, rows int,
	resizeCh <-chan *remotecommand.TerminalSize,
) error

RunK8sPodWebTTY runs an interactive shell in a Kubernetes pod with TTY over stdin/stdout/stderr, using the same dial path as the CLI (ephemeral debug container). Resize events are consumed from resizeCh.

func RunLogTUI added in v0.3.1

func RunLogTUI(ctx context.Context, user string, records []hosts.Record, opts LogOptions, cache *ClientCache) error

RunLogTUI starts the interactive log viewer.

func RunRecordingReplay added in v0.2.8

func RunRecordingReplay(recordDir, baseName string) error

RunRecordingReplay plays one .hrec.jsonl in a nested full-screen Bubble Tea view.

func RunSSHInteractive added in v0.3.4

func RunSSHInteractive(user string, r hosts.Record, rec any) error

RunSSHInteractive is the StandardRegistry implementation of RunInteractive.

func RunTable

func RunTable(records []hosts.Record, sshUser string, opts RunTableOptions) error

RunTable shows an interactive table and optionally execs ssh. After SSH/Tunnel disconnects, it returns to the UI.

func RunTerminalInteractive added in v0.2.9

func RunTerminalInteractive(user string, r hosts.Record, console string, reg hostexec.Registry) error

RunTerminalInteractive opens an interactive session (SSH, K8s, Docker, TrueNAS API shell, or Proxmox) on os.Stdin/Stdout.

func RunTrueNASTunnel added in v0.3.0

func RunTrueNASTunnel(ctx context.Context, _ string, r hosts.Record, localFwd string, out io.Writer) error

RunTrueNASTunnel listens locally and forwards each connection through the TrueNAS API shell dial bridge into the guest at remoteHost:remotePort (as seen from inside the guest).

func SSHClientCacheKey added in v0.2.8

func SSHClientCacheKey(user string, r hosts.Record) string

SSHClientCacheKey is the stable cache key for a pooled SSH client for (user, record).

func StartK8sPortForward added in v0.3.0

func StartK8sPortForward(ctx context.Context, r hosts.Record, localPort, remotePort int) (host string, port int, stop func(), err error)

StartK8sPortForward starts a non-blocking k8s port-forward; returns local listen host/port after readyCh.

func StartTrueNASForward added in v0.3.0

func StartTrueNASForward(ctx context.Context, user string, r hosts.Record, localFwd string) (host string, port int, stop func(), err error)

StartTrueNASForward starts a non-blocking TrueNAS API shell tunnel.

func StreamCueRecipeSteps

func StreamCueRecipeSteps(ctx context.Context, p CueRecipeRunParams, out chan<- HostExecResult) error

StreamCueRecipeSteps executes a CUE recipe step-by-step, streaming results.

func StreamLogs added in v0.3.1

func StreamLogs(ctx context.Context, user string, records []hosts.Record, opts LogOptions, cache *ClientCache, out io.Writer) error

StreamLogs streams logs for records to out with stable per-record prefixes.

func StreamSFTPDownloadParallel

func StreamSFTPDownloadParallel(ctx context.Context, user string, jobs []SFTPDownloadJob, out chan<- HostExecResult, opts BatchOptions) error

StreamSFTPDownloadParallel downloads files from multiple hosts in parallel.

func StreamSFTPUploadParallel

func StreamSFTPUploadParallel(ctx context.Context, user string, recs []hosts.Record, localAbs, remotePath string, out chan<- HostExecResult, opts BatchOptions) error

StreamSFTPUploadParallel uploads the same local file to remotePath on each record (SFTP over DialHoneyClient). Failures on one host do not cancel others.

func StreamSSHParallel

func StreamSSHParallel(ctx context.Context, user string, jobs []hosts.Record, kvTunnel bool, remoteCmd SSHRemoteCmdFunc, out chan<- HostExecResult, opts BatchOptions) error

StreamSSHParallel runs the command on records and streams results to out channel. It does not close the channel itself.

func StreamScriptContentRunParallel added in v0.3.4

func StreamScriptContentRunParallel(ctx context.Context, user string, recs []hosts.Record, scriptContent, fileExtension string, scriptOpts ScriptUploadRunOptions, out chan<- HostExecResult, opts BatchOptions) error

StreamScriptContentRunParallel writes scriptContent to a local temp file, uploads it to each host, runs it using Rundeck-style script-file semantics, and removes the local temp file afterwards.

func StreamScriptUploadRunParallel

func StreamScriptUploadRunParallel(ctx context.Context, user string, recs []hosts.Record, localAbs, remotePath string, kvTunnel bool, remoteCmd SSHRemoteCmdFunc, out chan<- HostExecResult, opts BatchOptions) error

StreamScriptUploadRunParallel uploads a script and executes it on multiple hosts in parallel.

func StreamScriptUploadRunParallelWithOptions added in v0.3.4

func StreamScriptUploadRunParallelWithOptions(ctx context.Context, user string, recs []hosts.Record, localAbs, remotePath string, kvTunnel bool, remoteCmd SSHRemoteCmdFunc, scriptOpts ScriptUploadRunOptions, out chan<- HostExecResult, opts BatchOptions) error

StreamScriptUploadRunParallelWithOptions uploads a script and executes it with optional interpreter/cleanup behavior.

func TransferStagingObjectKey added in v0.2.8

func TransferStagingObjectKey(cloud AgentCloudBackend, src, dst hosts.Record) string

TransferStagingObjectKey builds a unique object key when the caller leaves cloud.Object empty.

func TruenasTunnelRunner added in v0.3.4

func TruenasTunnelRunner() truenasprovider.TunnelRunner

TruenasTunnelRunner returns the ui-backed TrueNAS API-shell port-forward runner, injected into the truenas provider factory by the composition root.

func TruenasUpstreamDialer added in v0.3.4

func TruenasUpstreamDialer() truenasprovider.UpstreamDialer

TruenasUpstreamDialer returns the ui-backed TrueNAS API-shell upstream dialer.

func TruncateCueTranscript added in v0.2.8

func TruncateCueTranscript(s string, maxChars int) string

TruncateCueTranscript limits transcript size for LLM input; keeps head and tail with a banner if truncated.

func TunnelLookupKeyForShare added in v0.3.0

func TunnelLookupKeyForShare(shareKey, derivedKey string) string

TunnelLookupKeyForShare returns a stable global pool key from recipe tunnel config.

func WrapRecordingReader added in v0.2.8

func WrapRecordingReader(inner io.Reader, recorder *SessionRecorder, direction string) io.Reader

WrapRecordingReader returns a Reader that tees reads into recorder when non-nil.

func WrapRecordingWriter added in v0.2.8

func WrapRecordingWriter(inner io.Writer, recorder *SessionRecorder, direction string) io.Writer

WrapRecordingWriter returns a Writer that tees writes into recorder when non-nil.

func WriteCueKVTunnelDryLine added in v0.2.8

func WriteCueKVTunnelDryLine(out io.Writer, recipe cuetry.Recipe, stepIdx int, step cuetry.Step, def *cuetry.RecipeDefaults)

WriteCueKVTunnelDryLine prints one plan line when kv_tunnel is enabled for the step or defaults.

func WriteCueSSHPrivateKeyDryLine added in v0.2.9

func WriteCueSSHPrivateKeyDryLine(out io.Writer, stepIdx int, step cuetry.Step, def *cuetry.RecipeDefaults)

WriteCueSSHPrivateKeyDryLine prints one plan line when ssh_private_key is set for the step or defaults.

func WriteCueStepHooksDryLines added in v0.2.8

func WriteCueStepHooksDryLines(out io.Writer, stepIdx int, step cuetry.Step)

WriteCueStepHooksDryLines prints one plan line per configured hook (no secrets).

func WriteCueStepNotifyDryLine added in v0.2.8

func WriteCueStepNotifyDryLine(out io.Writer, step cuetry.Step)

WriteCueStepNotifyDryLine prints one plan line when notify is enabled (boolean only; no secrets).

func WriteCueStepRetryDryLine added in v0.3.0

func WriteCueStepRetryDryLine(out io.Writer, stepIdx int, cfg cuetry.RecipeStepRetry)

WriteCueStepRetryDryLine prints retry settings when enabled.

Types

type AgentCloudBackend added in v0.2.8

type AgentCloudBackend struct {
	Provider string `json:"provider"`
	Bucket   string `json:"bucket"`
	Prefix   string `json:"prefix,omitempty"`
	Object   string `json:"object,omitempty"`
	Region   string `json:"region,omitempty"`
	Endpoint string `json:"endpoint,omitempty"`
}

AgentCloudBackend describes the cloud object target path for staging.

type AgentTransferEndpoint added in v0.2.8

type AgentTransferEndpoint struct {
	Record hosts.Record `json:"record"`
	Path   string       `json:"path"`
}

AgentTransferEndpoint identifies one source/destination endpoint for transfer.

type AgentTransferEvent added in v0.2.8

type AgentTransferEvent struct {
	Stage     string    `json:"stage"`
	Host      string    `json:"host,omitempty"`
	Success   bool      `json:"success"`
	Message   string    `json:"message,omitempty"`
	Error     string    `json:"error,omitempty"`
	Attempt   int       `json:"attempt,omitempty"`
	Timestamp time.Time `json:"timestamp"`
}

AgentTransferEvent is emitted for each orchestration stage.

func ExecuteAgentCloudTransfer added in v0.2.8

func ExecuteAgentCloudTransfer(job AgentTransferJob, cache *ClientCache) ([]AgentTransferEvent, error)

ExecuteAgentCloudTransfer orchestrates source upload and destination download using ephemeral transfer agents over existing HostClient connections (SSH / k8s pod exec abstraction).

func ExecuteAgentCloudTransferWithEmit added in v0.2.8

func ExecuteAgentCloudTransferWithEmit(job AgentTransferJob, cache *ClientCache, emit func(AgentTransferEvent)) ([]AgentTransferEvent, error)

ExecuteAgentCloudTransferWithEmit runs the transfer and calls emit for each event.

func RunAgentTransferWithFallback added in v0.2.8

func RunAgentTransferWithFallback(
	ctx context.Context,
	cache *ClientCache,
	sshUser, agentOverride, preferredAgentPath, agentBuildCacheDir, agentRemoteDir string,
	src, dst hosts.Record,
	srcPath, dstPath string,
	cloud AgentCloudBackend,
	keepObject bool,
	maxRetries int,
	hints cloudtransfer.SigningHints,
	transferCfg config.TransferConfigEffective,
	emit func(AgentTransferEvent),
) ([]AgentTransferEvent, error)

RunAgentTransferWithFallback runs Build + Execute, transparently retrying via the agent path on fallback-path failure when transferCfg.PresignedRetryWithAgent is true. Returns the combined event timeline across both attempts so the caller always sees the full record.

emit may be nil; when non-nil it receives events as they happen for both attempts (the original fallback-path attempt and the agent-path retry).

type AgentTransferJob added in v0.2.8

type AgentTransferJob struct {
	SSHUser                 string                `json:"ssh_user"`
	ResolvedSourceUser      string                `json:"resolved_source_user"`
	ResolvedDestUser        string                `json:"resolved_dest_user"`
	AgentLocalPath          string                `json:"agent_local_path"`
	SourceAgentLocalPath    string                `json:"source_agent_local_path,omitempty"`
	DestAgentLocalPath      string                `json:"dest_agent_local_path,omitempty"`
	AgentRemoteDir          string                `json:"agent_remote_dir,omitempty"`
	Source                  AgentTransferEndpoint `json:"source"`
	Destination             AgentTransferEndpoint `json:"destination"`
	Cloud                   AgentCloudBackend     `json:"cloud"`
	CredentialProvider      string                `json:"credential_provider,omitempty"`
	CredentialEnv           map[string]string     `json:"credential_env,omitempty"`
	CredentialExpiresAtUnix int64                 `json:"credential_expires_at_unix,omitempty"`
	KeepObject              bool                  `json:"keep_object,omitempty"`
	MaxRetries              int                   `json:"max_retries,omitempty"`
	// FallbackPlan is non-nil when the curl-based presigned-URL transport should be
	// used instead of the staged-agent path. See docs/superpowers/specs/2026-05-12-presigned-url-transfer-path-design.md.
	FallbackPlan          *presign.Plan `json:"-"`
	FallbackCapabilitySrc string        `json:"-"`
	FallbackCapabilityDst string        `json:"-"`
	// RetryWithAgentOnCurlFailure controls whether a fallback-path failure transparently
	// retries via the agent path.
	RetryWithAgentOnCurlFailure bool `json:"retry_with_agent_on_curl_failure,omitempty"`
}

AgentTransferJob describes one A->cloud->B transfer orchestration request.

func BuildAgentTransferJob added in v0.2.8

func BuildAgentTransferJob(
	ctx context.Context,
	cache *ClientCache,
	sshUser, agentOverride, preferredAgentPath, agentBuildCacheDir, agentRemoteDir string,
	src, dst hosts.Record,
	srcPath, dstPath string,
	cloud AgentCloudBackend,
	keepObject bool,
	maxRetries int,
	hints cloudtransfer.SigningHints,
	transferCfg config.TransferConfigEffective,
) (AgentTransferJob, error)

BuildAgentTransferJob wires cloud credentials, per-target agent binaries, and staging object key. preferredAgentPath is used when agentOverride is empty (e.g. web server default binary); agentBuildCacheDir overrides the directory for cross-compiled agents (empty uses HONEY_TRANSFER_AGENT_CACHE or os temp).

transferCfg controls whether the fallback-path (presigned-URL) transport is attempted before falling back to staging the transfer-agent binary. When transferCfg.ForceAgentPath is true, the curl branch is bypassed.

type AgentTransferValidationError added in v0.2.8

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

AgentTransferValidationError indicates user/input issues (HTTP 400).

func (*AgentTransferValidationError) Error added in v0.2.8

type AppDialerTransport added in v0.3.1

type AppDialerTransport string

AppDialerTransport describes the transport used to reach an app upstream.

const (
	// AppDialerTransportSSH means the upstream is reached through a regular SSH client.
	AppDialerTransportSSH AppDialerTransport = "ssh"
	// AppDialerTransportInMemory means the upstream is reached through a provider-native tunnel.
	AppDialerTransportInMemory AppDialerTransport = "in-memory"
)

func TransportForAppDialer added in v0.3.1

func TransportForAppDialer(rec hosts.Record) AppDialerTransport

TransportForAppDialer returns the transport family used for a record's app upstream connection.

type BatchOptions added in v0.3.4

type BatchOptions struct {
	MaxConc        int
	Cache          *ClientCache
	RecipeKV       *RecipeKVCoordinator
	RecipeScopedKV bool
	Post           SSHPostHostResultFunc
	RetryCfg       cuetry.RecipeStepRetry
	Obs            metrics.Observer
	AttemptMax     *atomic.Int32
	Reg            hostexec.Registry
}

BatchOptions groups the cross-cutting knobs shared by the parallel SSH/SFTP/script runners (previously trailing positional parameters). Zero values are valid: a nil Cache makes the runner build a short-lived one from Reg; a nil AttemptMax/Obs disables the corresponding bookkeeping.

type ClientCache

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

ClientCache maintains a pool of open HostClient connections for reuse across steps.

func NewClientCache

func NewClientCache() *ClientCache

NewClientCache creates a new uninitialized cache. You must call SetRegistry on it before it can dial properly.

func (*ClientCache) AcquireLease added in v0.3.1

func (c *ClientCache) AcquireLease(user string, r hosts.Record) (*ClientLease, error)

AcquireLease returns a cached client and tracks a lightweight borrow for app proxy sessions.

func (*ClientCache) BorrowSSH added in v0.3.4

func (c *ClientCache) BorrowSSH(user string, hop hosts.Record) (interface{}, bool)

BorrowSSH is used to wire up the ExecRegistry SSHBorrower.

func (*ClientCache) CloseAll

func (c *ClientCache) CloseAll()

CloseAll closes all cached connections and clears the cache.

func (*ClientCache) Evict added in v0.2.8

func (c *ClientCache) Evict(user string, r hosts.Record)

Evict removes the cached client for this host (if any) and closes it so the next GetOrDial establishes a fresh connection.

func (*ClientCache) GetOrDial

func (c *ClientCache) GetOrDial(user string, r hosts.Record) (HostClient, error)

GetOrDial returns an existing connection or dials a new one and stores it.

func (*ClientCache) SetRegistry added in v0.3.4

func (c *ClientCache) SetRegistry(reg hostexec.Registry)

SetRegistry configures the executor registry.

type ClientLease added in v0.3.1

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

ClientLease is a borrowed cached host connection. Close releases the borrow without directly closing the shared underlying connection.

func (*ClientLease) Close added in v0.3.1

func (l *ClientLease) Close() error

Close releases the lease. The cached connection remains available until eviction or CloseAll.

func (*ClientLease) HostClient added in v0.3.1

func (l *ClientLease) HostClient() HostClient

HostClient returns the borrowed client.

type CloudBackendRef added in v0.2.8

type CloudBackendRef struct {
	Kind  string `json:"kind"`
	Name  string `json:"name,omitempty"`
	Index *int   `json:"index,omitempty"`
}

CloudBackendRef selects a backend entry from honey YAML for agent-transfer signing hints.

type CueRecipeRunParams added in v0.3.4

type CueRecipeRunParams struct {
	Recipe         cuetry.Recipe
	RecipeDir      string
	Records        []hosts.Record
	SSHUser        string
	CLIEnv         map[string]string
	ConfigPath     string
	AISystemPrompt string
	SecretResolver cuetry.SecretResolver
	PluginMgr      *plugins.Manager
	Execute        bool
	JSON           bool
	Obs            metrics.Observer
	Reg            hostexec.Registry
	Pools          *postgres.PoolManager
}

CueRecipeRunParams carries the inputs for StreamCueRecipeSteps. Grouping these (previously 15 positional parameters) keeps the public call sites readable and stable as the recipe engine grows.

ConfigPath is the resolved honey YAML path (may be empty); agent_transfer steps with cloud_backend_ref require it. AISystemPrompt is defaults.ai_system_prompt (already loaded), used only for the terminal ai step.

type DockerTerminalSize added in v0.3.0

type DockerTerminalSize = dockerprovider.DockerTerminalSize

DockerTerminalSize is a cols/rows pair for docker exec resize. It is an alias for dockerprovider.DockerTerminalSize.

type Executor

type Executor = hostexec.Executor

Executor aliases the shared executor interface.

type GlobalTunnelPool added in v0.3.0

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

GlobalTunnelPool caches active tunnels keyed by share_key or derived spec hash.

func DefaultGlobalTunnelPool added in v0.3.0

func DefaultGlobalTunnelPool() *GlobalTunnelPool

DefaultGlobalTunnelPool returns the process-wide tunnel pool.

func NewGlobalTunnelPool added in v0.3.0

func NewGlobalTunnelPool(ttl time.Duration) *GlobalTunnelPool

NewGlobalTunnelPool creates a pool with the given idle TTL (0 = default 30m).

func (*GlobalTunnelPool) Acquire added in v0.3.0

func (p *GlobalTunnelPool) Acquire(ctx context.Context, key string, factory func(context.Context) (TunnelEndpoint, func(), error)) (TunnelEndpoint, func(), error)

Acquire returns an endpoint, creating via factory on miss. release() decrements refcount.

func (*GlobalTunnelPool) Close added in v0.3.0

func (p *GlobalTunnelPool) Close()

Close stops all entries and the sweeper.

type HostClient

type HostClient = hostexec.HostClient

HostClient aliases the shared execution interface (see internal/hostexec).

type HostExecResult

type HostExecResult struct {
	Name          string
	IP            string
	Provider      string
	Success       bool
	Skipped       bool // when CEL was false; no SSH/SFTP ran
	Changed       bool // true if mutation occurred (e.g. check_cmd was absent, or check_cmd failed)
	ExitCode      int
	Output        string
	OutputCapture string // named CUE output capture; display may suppress successful stdout
	ErrMsg        string // transport / spawn failure (not remote stderr)

	// HookPhase / HookOutput are set when a CUE step hook ran after the main result (command/script only).
	HookPhase  string // "on_success" or "on_failure"
	HookOutput string // captured stdout+stderr from the hook (local or remote)
	HookFailed bool   // true if the hook execution failed
}

HostExecResult is the outcome of one non-interactive ssh run.

func ExecuteSFTPDownloadParallel

func ExecuteSFTPDownloadParallel(user string, jobs []SFTPDownloadJob, maxConc int) ([]HostExecResult, error)

ExecuteSFTPDownloadParallel runs each download job (possibly different local paths per host) in parallel.

func ExecuteSFTPUploadParallel

func ExecuteSFTPUploadParallel(user string, recs []hosts.Record, localAbs, remotePath string, maxConc int) ([]HostExecResult, error)

ExecuteSFTPUploadParallel executes an SFTP upload in parallel across multiple hosts and returns results synchronously.

func ExecuteSSHParallel

func ExecuteSSHParallel(user string, recs []hosts.Record, remoteCmdFunc func(hosts.Record) string, maxConc int, reg hostexec.Registry) ([]HostExecResult, error)

ExecuteSSHParallel runs the same remote shell command on every record that has PrimaryIP set. Failures on individual hosts do not cancel others. It uses DialHoneyClient (golang.org/x/crypto/ssh + ~/.ssh/config) with known_hosts verification.

func ExecuteScriptContentRunParallel added in v0.3.4

func ExecuteScriptContentRunParallel(user string, recs []hosts.Record, scriptContent, fileExtension string, opts ScriptUploadRunOptions, maxConc int, reg hostexec.Registry) ([]HostExecResult, error)

ExecuteScriptContentRunParallel writes scriptContent to a local temp file, uploads it to each host, runs it using Rundeck-style script-file semantics in parallel, and returns results synchronously.

func ExecuteScriptUploadRunParallel

func ExecuteScriptUploadRunParallel(user string, recs []hosts.Record, localAbs, remotePath, remoteCmd string, maxConc int) ([]HostExecResult, error)

ExecuteScriptUploadRunParallel uploads localAbs to remotePath on each host over SFTP, then runs remoteCmd on the same SSH connection (one session per host per step).

func RunOneSFTPUploadWithProgress added in v0.2.8

func RunOneSFTPUploadWithProgress(user string, r hosts.Record, localAbs, remotePath string, cache *ClientCache, onProgress func(written, total int64)) HostExecResult

RunOneSFTPUploadWithProgress uploads one local file to remotePath on r, like runOneSFTPUpload. onProgress is optional; it receives cumulative bytes written toward the remote and the local file size. Live updates are emitted for *sshclient.HoneyClient (SFTP); other executors only report start/end.

func SortHostExecForUI

func SortHostExecForUI(s []HostExecResult) []HostExecResult

SortHostExecForUI orders failures first, then host name (case-insensitive).

type HostExecRetryOutcome added in v0.3.0

type HostExecRetryOutcome struct {
	Result              HostExecResult
	Attempts            int
	LastAttemptDuration time.Duration
}

HostExecRetryOutcome is the result of runHostExecWithRetry.

type KVTunnelProvider added in v0.3.4

type KVTunnelProvider interface {
	SupportsKVTunnel() bool
}

KVTunnelProvider is an optional interface that HostClients can implement if they natively support or explicitly reject bootstrapping KV tunnels.

type LocalFileEntry added in v0.2.8

type LocalFileEntry struct {
	Name       string    `json:"name"`
	Path       string    `json:"path"`
	IsDir      bool      `json:"is_dir"`
	Size       int64     `json:"size"`
	Mode       string    `json:"mode"`
	ModifiedAt time.Time `json:"modified_at"`
}

LocalFileEntry mirrors RemoteFileEntry for local directories.

func ListLocalDirUnderRoot added in v0.2.8

func ListLocalDirUnderRoot(root, requested string) (string, []LocalFileEntry, error)

ListLocalDirUnderRoot lists a directory under the resolved root path.

type LogOptions added in v0.3.1

type LogOptions struct {
	Target                 string
	Source                 string
	Follow                 bool
	Tail                   int64
	Since                  time.Duration
	Timestamps             bool
	Container              string
	Unit                   string
	Command                string
	RunAs                  string
	MaxConcurrency         int
	Grep                   string
	Labels                 []string
	Highlight              bool
	Anomaly                bool
	AnomalyModel           string
	AnomalyThresh          float64
	AnomalyWindow          int
	AnomalyOnly            bool
	AnomalyStrict          bool
	AnomalyTokPath         string
	AnomalyEndpoint        string
	AnomalyLLMModel        string
	AnomalyContextLines    int
	AnomalyFilterThreshold float64
	AnomalyFreqWindow      int
	AnomalyFreqRatio       float64
	AnomalyFeedbackFile    string
	AnomalyPreprocessor    string
	AlertEnabled           bool
	AlertSuppressDuration  time.Duration
}

LogOptions controls distributed log streaming.

type LogViewModel added in v0.3.1

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

LogViewModel is the Bubble Tea model for the log viewer.

func NewLogViewModel added in v0.3.1

func NewLogViewModel(opts LogOptions) *LogViewModel

NewLogViewModel creates a new log view model.

func (*LogViewModel) Init added in v0.3.1

func (m *LogViewModel) Init() tea.Cmd

Init initializes the log view model.

func (*LogViewModel) Update added in v0.3.1

func (m *LogViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages and updates the log view model.

func (*LogViewModel) View added in v0.3.1

func (m *LogViewModel) View() tea.View

View renders the log viewer UI.

type RecipeKVCoordinator added in v0.2.8

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

RecipeKVCoordinator owns one operator-side stepkv session for a cue-exec run and one forward (SSH remote-forward or k8s exec bridge) per cached client key. The mutex is only held while the per-key placeholder is reserved; the slow handshake runs outside the lock so parallel hosts don't serialize.

func NewRecipeKVCoordinator added in v0.2.8

func NewRecipeKVCoordinator(ttl time.Duration) *RecipeKVCoordinator

NewRecipeKVCoordinator constructs a coordinator; ttl defaults to stepKVTunnelTTL when <= 0.

func (*RecipeKVCoordinator) Close added in v0.2.8

func (c *RecipeKVCoordinator) Close()

Close stops all remote listeners / k8s bridges and closes the stepkv session.

func (*RecipeKVCoordinator) EnsureK8sExecBridgeEnv added in v0.2.8

func (c *RecipeKVCoordinator) EnsureK8sExecBridgeEnv(user string, r hosts.Record, k8c *k8sNativeClient) (map[string]string, error)

EnsureK8sExecBridgeEnv returns HONEY_KV_* for this pod by multiplexing pod loopback HTTP to the shared stepkv session over a long-lived kubectl exec.

func (*RecipeKVCoordinator) EnsureKVTunnelEnv added in v0.2.8

func (c *RecipeKVCoordinator) EnsureKVTunnelEnv(user string, r hosts.Record, hc *sshclient.HoneyClient) (map[string]string, error)

EnsureKVTunnelEnv returns HONEY_KV_* for this host's remote-forward into the shared session.

func (*RecipeKVCoordinator) EnsureSession added in v0.2.9

func (c *RecipeKVCoordinator) EnsureSession() (*stepkv.Session, error)

EnsureSession returns the shared stepkv session, creating it if needed (no SSH forward).

func (*RecipeKVCoordinator) EnsureTrueNASAPIShellBridgeEnv added in v0.3.0

func (c *RecipeKVCoordinator) EnsureTrueNASAPIShellBridgeEnv(ctx context.Context, user string, r hosts.Record, cache *ClientCache) (map[string]string, error)

EnsureTrueNASAPIShellBridgeEnv attaches kv_tunnel for a TrueNAS row into the shared recipe stepkv session.

func (*RecipeKVCoordinator) InvalidateHost added in v0.2.8

func (c *RecipeKVCoordinator) InvalidateHost(user string, r hosts.Record)

InvalidateHost tears down this host's remote-forward or k8s exec bridge only (e.g. after cache evict). The shared stepkv session stays open for other hosts.

type RecipeMeta added in v0.2.8

type RecipeMeta struct {
	RecipePath        string         `json:"recipe_path"`
	HostCount         int            `json:"host_count"`
	RecipeContentHash string         `json:"recipe_content_hash"`
	StartedAt         time.Time      `json:"started_at"`
	Hosts             []hosts.Record `json:"hosts,omitempty"`
}

RecipeMeta describes the recipe that a cue-exec batch is about to run. Recorded into the session file so a later "recent runs" enumeration can attribute the recording to a recipe and detect in-browser edits.

type RecipeTunnelCoordinator added in v0.3.0

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

RecipeTunnelCoordinator tracks tunnel endpoints for one cue-exec run and releases pool refs on Close.

func NewRecipeTunnelCoordinator added in v0.3.0

func NewRecipeTunnelCoordinator(pool *GlobalTunnelPool) *RecipeTunnelCoordinator

NewRecipeTunnelCoordinator creates a coordinator backed by the process-wide pool.

func (*RecipeTunnelCoordinator) Acquire added in v0.3.0

func (c *RecipeTunnelCoordinator) Acquire(ctx context.Context, key string, factory func(context.Context) (TunnelEndpoint, func(), error)) (TunnelEndpoint, func(), error)

Acquire obtains or creates a tunnel from the global pool.

func (*RecipeTunnelCoordinator) Close added in v0.3.0

func (c *RecipeTunnelCoordinator) Close()

Close releases all pool references held by this run.

func (*RecipeTunnelCoordinator) Lookup added in v0.3.0

func (c *RecipeTunnelCoordinator) Lookup(stepID, user string, r hosts.Record) (TunnelEndpoint, bool)

Lookup returns the endpoint for a tunnel step id and host.

func (*RecipeTunnelCoordinator) LookupEndpoint added in v0.3.0

func (c *RecipeTunnelCoordinator) LookupEndpoint(stepID, user string, r hosts.Record) (string, int, bool)

LookupEndpoint implements plugins.TunnelCoordinator for postgres DSN rewrite.

func (*RecipeTunnelCoordinator) Register added in v0.3.0

func (c *RecipeTunnelCoordinator) Register(stepID, user string, r hosts.Record, ep TunnelEndpoint, release func())

Register stores an endpoint for tunnel_step lookup and holds the pool release until Close.

type RemoteFileEntry added in v0.2.8

type RemoteFileEntry = hostexec.RemoteFileEntry

RemoteFileEntry aliases remote file metadata for JSON APIs.

func RemoteListDir added in v0.2.8

func RemoteListDir(user string, record hosts.Record, remotePath string, cache *ClientCache) ([]RemoteFileEntry, error)

RemoteListDir lists a directory on the remote host using a cached SSH/k8s client.

type RunTableOptions added in v0.2.8

type RunTableOptions struct {
	RecordDir     string
	RecordEnabled bool
	// Config is the honey YAML already loaded for this session (optional; nil if none / load failed).
	Config *config.File
	// ConfigPath is the resolved honey YAML path (may be empty); CUE agent_transfer steps with cloud_backend_ref need it.
	ConfigPath string
	// ClientCache is an optional shared SSH client cache. If nil, one is created.
	ClientCache *ClientCache
	// ExecRegistry is the host execution registry.
	ExecRegistry hostexec.Registry
	// AlertBanner is an optional one-line banner shown above the table (e.g. from `honey alert investigate`).
	AlertBanner string
}

RunTableOptions configures optional session recording for the TUI table.

type SFTPDownloadJob

type SFTPDownloadJob struct {
	Record     hosts.Record
	LocalAbs   string
	RemotePath string
}

SFTPDownloadJob is one remote→local file copy for a specific host.

type SSHPostHostResultFunc added in v0.2.8

type SSHPostHostResultFunc func(ctx context.Context, r hosts.Record, res *HostExecResult)

SSHPostHostResultFunc runs after each host's main SSH run and before the result is emitted (e.g. CUE step hooks). It may set res.HookPhase and res.HookOutput. Hook failures must not change the original step success fields.

type SSHRemoteCmdFunc added in v0.2.8

type SSHRemoteCmdFunc func(r hosts.Record, kv map[string]string) string

SSHRemoteCmdFunc builds the remote shell string. kv is nil when kv_tunnel is disabled; otherwise it contains HONEY_KV_URL (reachable from the remote via SSH remote forward) and HONEY_KV_TOKEN for Authorization.

type ScriptUploadRunOptions added in v0.3.4

type ScriptUploadRunOptions struct {
	ScriptInterpreter     string
	InterpreterArgsQuoted bool
	RemoveRemoteFile      bool
	// ScriptArgs are positional arguments passed to the script (Rundeck-style),
	// shell-quoted and appended after the interpreter/path.
	ScriptArgs []string
	// RunAs wraps the run step in sudo for that user (empty = run as the SSH user).
	RunAs string
}

ScriptUploadRunOptions controls upload/chmod/execute script runs.

type SessionRecorder added in v0.2.8

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

SessionRecorder appends JSONL events to a single .hrec.jsonl file (TTY data, resize, errors, close).

func NewBatchSessionRecorder added in v0.2.8

func NewBatchSessionRecorder(dir, trigger, user string, jobCount int) (*SessionRecorder, error)

NewBatchSessionRecorder creates a recorder for one parallel exec or CUE batch run (one file per invocation).

func NewSessionRecorder added in v0.2.8

func NewSessionRecorder(opts SessionRecorderOptions) (*SessionRecorder, error)

NewSessionRecorder creates a recorder writing to opts.Dir with a timestamped filename.

func (*SessionRecorder) Close added in v0.2.8

func (r *SessionRecorder) Close() error

Close writes a "close" event and closes the underlying file.

func (*SessionRecorder) Path added in v0.2.8

func (r *SessionRecorder) Path() string

Path returns the absolute path of the recording file, or empty if r is nil.

func (*SessionRecorder) RecordData added in v0.2.8

func (r *SessionRecorder) RecordData(direction string, payload []byte)

RecordData writes a base64-encoded payload for the given direction (e.g. in/out).

func (*SessionRecorder) RecordError added in v0.2.8

func (r *SessionRecorder) RecordError(err error)

RecordError records a non-fatal error message on the session.

func (*SessionRecorder) RecordHostExecResult added in v0.2.8

func (r *SessionRecorder) RecordHostExecResult(res HostExecResult)

RecordHostExecResult writes one structured "result" event (parallel exec / batch output).

func (*SessionRecorder) RecordRecipeMeta added in v0.2.8

func (r *SessionRecorder) RecordRecipeMeta(meta RecipeMeta)

RecordRecipeMeta writes one "recipe-meta" structured event into the recording. Safe to call on a nil recorder.

func (*SessionRecorder) RecordResize added in v0.2.8

func (r *SessionRecorder) RecordResize(cols, rows int)

RecordResize records a terminal resize event.

func (*SessionRecorder) RecordingFileBase added in v0.3.0

func (r *SessionRecorder) RecordingFileBase() string

RecordingFileBase returns the recording filename (e.g. 20260102_120000_web-cue-exec_batch_mixed_batch-3.hrec.jsonl).

func (*SessionRecorder) RecordingID added in v0.3.0

func (r *SessionRecorder) RecordingID() string

RecordingID returns the recording id (filename without .hrec.jsonl).

type SessionRecorderOptions added in v0.2.8

type SessionRecorderOptions struct {
	Dir      string
	Trigger  string
	Mode     string
	Provider string
	HostName string
	HostIP   string
	User     string
	// HostSegment, when set, is used for the filename segment instead of HostName/IP (e.g. batch-12).
	HostSegment string
}

SessionRecorderOptions configures filename segments and metadata for a new session recording.

type TunnelEndpoint added in v0.3.0

type TunnelEndpoint struct {
	Host       string
	Port       int
	Mode       string
	TunName    string
	RemoteHost string
	RemotePort int
	ShareKey   string
}

TunnelEndpoint describes an operator-side listen address for a recipe tunnel.

Jump to

Keyboard shortcuts

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