remotehost

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package remotehost is the fairpeer remote-workspace host: a headless process (spawned inside WSL, a container, or over SSH) that owns the real controllers for remote workspaces and exposes them to the desktop over a stdio NDJSON JSON-RPC connection. The desktop is a thin client: turns, tools, files, git, and session storage all execute on this side.

The wire protocol reuses internal/acp's Conn (a transport-agnostic bidirectional JSON-RPC 2.0 link). Unlike ACP — an editor-facing protocol with its own update vocabulary — this surface mirrors what the desktop drives on a local *control.Controller, and the event stream uses the shared eventwire shape, so a remote tab's UI is pixel-equivalent to a local one.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ListenServe

func ListenServe(ctx context.Context, addr, token, certDir string, factory Factory, info HelloInfo, configure ConfigureFunc, hasModel HasModelConfigFunc) error

ListenServe runs a remote host as a TCP server (the Server connection kind): every accepted connection speaks the same NDJSON JSON-RPC protocol after a one-line token handshake. Sessions are shared across connections, so a desktop can reconnect without losing state. An empty token refuses the handshake (Server mode requires one).

certDir non-empty upgrades the listener to TLS with a self-signed certificate persisted there (generated on first start, reused afterwards so the desktop's pinned fingerprint survives restarts).

func Serve

func Serve(ctx context.Context, r io.Reader, w io.Writer, factory Factory, info HelloInfo, configure ConfigureFunc, hasModel HasModelConfigFunc) error

Serve runs a remote host on r/w (stdin/stdout in production) until the input ends or ctx is cancelled. stdout is the JSON-RPC channel; all diagnostics must go to stderr.

Types

type AnswerParams

type AnswerParams struct {
	SessionID string      `json:"sessionId"`
	ID        string      `json:"id"`
	Answers   []AskAnswer `json:"answers"`
}

type ApproveParams

type ApproveParams struct {
	SessionID string `json:"sessionId"`
	ID        string `json:"id"`
	Allow     bool   `json:"allow"`
	Session   bool   `json:"session"`
	Persist   bool   `json:"persist"`
}

type AskAnswer

type AskAnswer struct {
	QuestionID string   `json:"questionId"`
	Selected   []string `json:"selected"`
}

AskAnswer is the wire form of event.AskAnswer (which has no JSON tags).

type AskRequestParams

type AskRequestParams struct {
	SessionID string          `json:"sessionId"`
	Event     eventwire.Event `json:"event"` // the ask_request wire event
}

AskRequestParams is the outbound round-trip for ask_request events.

type AskRequestResult

type AskRequestResult struct {
	Answers []AskAnswer `json:"answers"`
}

type AuthParams

type AuthParams struct {
	Token string `json:"token"`
}

AuthParams is the mandatory first line of a Server-mode connection.

type BranchesResult

type BranchesResult struct {
	Branches json.RawMessage `json:"branches"` // []agent.BranchInfo
	Current  json.RawMessage `json:"current,omitempty"`
}

type CheckpointDiffParams

type CheckpointDiffParams struct {
	SessionID string `json:"sessionId"`
	Turn      int    `json:"turn"`
}

type CheckpointDiffResult

type CheckpointDiffResult struct {
	Changes json.RawMessage `json:"changes"` // []diff.Change
}

type CheckpointHasBoundaryResult

type CheckpointHasBoundaryResult struct {
	Has bool `json:"has"`
}

type CheckpointsResult

type CheckpointsResult struct {
	Checkpoints json.RawMessage `json:"checkpoints"` // []checkpoint.Meta
}

type CompactParams

type CompactParams struct {
	SessionID    string `json:"sessionId"`
	Instructions string `json:"instructions"`
}

type ConfigureFunc

type ConfigureFunc func(p ConfigureParams) (ConfigureResult, error)

type ConfigureParams

type ConfigureParams struct {
	DefaultModel string             `json:"defaultModel"`
	Providers    []ProviderSnapshot `json:"providers"`
}

ConfigureParams is the desktop pushing its model configuration so a fresh remote install can run without local setup. Keys land in the remote secret store; the provider entries land in the remote user config. Writing is skipped entirely when the remote side already has a usable provider.

type ConfigureResult

type ConfigureResult struct {
	Configured        bool `json:"configured"`
	AlreadyConfigured bool `json:"alreadyConfigured"`
}

type EventParams

type EventParams struct {
	SessionID string          `json:"sessionId"`
	Event     eventwire.Event `json:"event"`
}

EventParams carries one controller event for a session.

type Factory

type Factory interface {
	NewController(ctx context.Context, p SessionNewParams, sink event.Sink) (*control.Controller, error)
}

Factory assembles one session's controller, mirroring the desktop's buildTabController on the host side (config load for the root, model fallback resolution, per-project session dir, presentation sidecar). The production wiring lives in internal/cli; tests supply a stub.

type FollowUpParams

type FollowUpParams struct {
	SessionID string `json:"sessionId"`
	Input     string `json:"input"`
}

type ForkParams

type ForkParams struct {
	SessionID string `json:"sessionId"`
	Turn      int    `json:"turn"`
	Name      string `json:"name,omitempty"`
}

type ForkResult

type ForkResult struct {
	SessionPath string `json:"sessionPath"`
}

type FsEntry

type FsEntry struct {
	Name string `json:"name"`
	Dir  bool   `json:"dir"`
}

type FsListParams

type FsListParams struct {
	SessionID string `json:"sessionId"`
	Path      string `json:"path"` // relative to the session root; "" = root
}

type FsListResult

type FsListResult struct {
	Entries []FsEntry `json:"entries"`
}

type FsReadParams

type FsReadParams struct {
	SessionID string `json:"sessionId"`
	Path      string `json:"path"`
}

type FsReadResult

type FsReadResult struct {
	Kind      string `json:"kind"` // "text" | "image" | "pdf" | "video" | "audio" | "office" | "binary" | "missing"
	Mime      string `json:"mime,omitempty"`
	Text      string `json:"text,omitempty"`
	DataURL   string `json:"dataUrl,omitempty"`
	Size      int64  `json:"size"`
	Truncated bool   `json:"truncated,omitempty"`
}

type FsSearchParams

type FsSearchParams struct {
	SessionID string `json:"sessionId"`
	Query     string `json:"query"`
}

type FsSearchResult

type FsSearchResult struct {
	Results json.RawMessage `json:"results"` // []fileref.SearchResult
}

type GitEntry

type GitEntry struct {
	Path   string `json:"path"`
	Change string `json:"change"` // porcelain XY code, e.g. "M", "A", "??"
}

type GitStatusResult

type GitStatusResult struct {
	Root     string     `json:"root"`
	Branch   string     `json:"branch"` // "" + Detached on detached HEAD; empty repo → IsRepo=false
	Detached bool       `json:"detached"`
	IsRepo   bool       `json:"isRepo"`
	Entries  []GitEntry `json:"entries"`
	// Added/Removed are `git diff --numstat HEAD` line totals (binary "-"
	// columns skipped); a failed probe leaves both zero.
	Added   int `json:"added,omitempty"`
	Removed int `json:"removed,omitempty"`
}

type GoalStatusResult

type GoalStatusResult struct {
	Goal   string `json:"goal"`
	Status string `json:"status"`
}

type HasModelConfigFunc

type HasModelConfigFunc func() bool

type HelloInfo

type HelloInfo struct {
	Version    string
	Goos       string
	Arch       string
	Home       string
	ConfigRoot string
}

HelloInfo identifies the host build; ConfigureFunc and HasModelConfigFunc implement host/configure (see protocol.go). All three are optional — Serve answers host/hello with Version alone when they are nil.

type HelloResult

type HelloResult struct {
	Version    string `json:"version"`
	Goos       string `json:"goos"`
	Arch       string `json:"arch"`
	Home       string `json:"home"`
	ConfigRoot string `json:"configRoot"`
	// HasModelConfig reports whether this side already has at least one provider
	// with a resolvable API key (host/configure skips writing when true).
	HasModelConfig bool `json:"hasModelConfig"`
}

HelloResult is the reply to host/hello. The desktop compares Version against its own build to decide whether to re-provision the host binary.

type HistoryResult

type HistoryResult struct {
	Messages json.RawMessage `json:"messages"` // []provider.Message
}

type NewSessionParams

type NewSessionParams struct {
	SessionID string `json:"sessionId"`
}

type NewSessionResult

type NewSessionResult struct {
	SessionPath string `json:"sessionPath"`
}

type PermissionRequestParams

type PermissionRequestParams struct {
	SessionID string          `json:"sessionId"`
	Event     eventwire.Event `json:"event"` // the approval_request wire event
}

PermissionRequestParams is the outbound round-trip the host makes while the run loop is blocked on a gated tool call; the desktop replies with the user's decision (or an error/deny on disconnect).

type PermissionRequestResult

type PermissionRequestResult struct {
	Allow   bool `json:"allow"`
	Session bool `json:"session"`
	Persist bool `json:"persist"`
}

type PresentResult

type PresentResult struct {
	Records        json.RawMessage `json:"records"` // []present.Record
	RewriteVersion int             `json:"rewriteVersion"`
	OK             bool            `json:"ok"`
}

type ProviderSnapshot

type ProviderSnapshot struct {
	Name          string   `json:"name"`
	Kind          string   `json:"kind"`
	BaseURL       string   `json:"base_url,omitempty"`
	APIKeyEnv     string   `json:"apiKeyEnv,omitempty"`
	APIKey        string   `json:"apiKey,omitempty"` // written to the remote secret store
	Models        []string `json:"models,omitempty"`
	ContextWindow int      `json:"contextWindow,omitempty"`
	Vision        bool     `json:"vision,omitempty"`
}

ProviderSnapshot is one provider entry to mirror remotely.

type QueuedResult

type QueuedResult struct {
	Steer    []string `json:"steer"`
	FollowUp []string `json:"followUp"`
}

type RewindParams

type RewindParams struct {
	SessionID string `json:"sessionId"`
	Turn      int    `json:"turn"`
	Scope     string `json:"scope"` // "code" | "conversation" | "both"
}

type RewindPreviewResult

type RewindPreviewResult struct {
	Classes json.RawMessage `json:"classes"`
}

RewindPreviewResult carries the per-path safety classification ([]control.RewindFileClass) for a code-scope rewind preview.

type RunShellParams

type RunShellParams struct {
	SessionID string `json:"sessionId"`
	Command   string `json:"command"`
}

type SessionEntry

type SessionEntry struct {
	Path      string `json:"path"`
	ModTimeMs int64  `json:"modTimeMs"`
	// Enriched from the .meta sidecar when present (the same metadata the
	// desktop's local tree reads from its own session dirs).
	Turns         int    `json:"turns,omitempty"`
	TopicID       string `json:"topicId,omitempty"`
	TopicTitle    string `json:"topicTitle,omitempty"`
	WorkspaceRoot string `json:"workspaceRoot,omitempty"`
	Scope         string `json:"scope,omitempty"`
	Preview       string `json:"preview,omitempty"`
}

type SessionListParams

type SessionListParams struct {
	Cwd string `json:"cwd"`
}

SessionListParams enumerates the host-side transcripts stored under a root.

type SessionListResult

type SessionListResult struct {
	Sessions []SessionEntry `json:"sessions"`
}

type SessionNewParams

type SessionNewParams struct {
	SessionID        string `json:"sessionId,omitempty"` // caller-chosen id (desktop tab id); generated when empty
	Cwd              string `json:"cwd"`
	Model            string `json:"model,omitempty"`
	Effort           string `json:"effort,omitempty"`
	Profile          string `json:"profile,omitempty"`
	Mode             string `json:"mode,omitempty"` // normal | plan | yolo | plan-yolo
	ToolApprovalMode string `json:"toolApprovalMode,omitempty"`
	RagScope         string `json:"ragScope,omitempty"`
	Goal             string `json:"goal,omitempty"`
	// SessionPath pins the exact transcript to continue (tab restore); empty =
	// fresh session file.
	SessionPath string `json:"sessionPath,omitempty"`
}

SessionNewParams opens a session rooted at Cwd, mirroring the desktop's buildTabController: config load + model fallback resolution + boot.Build with the per-project session dir, then the tab's persisted mode knobs are applied.

type SessionNewResult

type SessionNewResult struct {
	SessionID   string `json:"sessionId"`
	SessionPath string `json:"sessionPath"`
	Label       string `json:"label"`
}

type SessionRef

type SessionRef struct {
	SessionID string `json:"sessionId"`
}

SessionRef addresses an existing session.

type SessionStateResult

type SessionStateResult struct {
	Running          bool    `json:"running"`
	Paused           bool    `json:"paused"`
	Label            string  `json:"label"`
	Model            string  `json:"model"`
	WorkspaceRoot    string  `json:"workspaceRoot"`
	SessionPath      string  `json:"sessionPath"`
	SessionDir       string  `json:"sessionDir"`
	ToolApprovalMode string  `json:"toolApprovalMode"`
	PlanMode         bool    `json:"planMode"`
	Goal             string  `json:"goal"`
	GoalStatus       string  `json:"goalStatus"`
	ContextUsed      int     `json:"contextUsed"`
	ContextWindow    int     `json:"contextWindow"`
	CompactRatio     float64 `json:"compactRatio"`
}

SessionStateResult batches the small getters the desktop polls per tab, so a remote reconcile costs one round-trip instead of six.

type SetGoalParams

type SetGoalParams struct {
	SessionID string `json:"sessionId"`
	Goal      string `json:"goal"`
}

type SetModeParams

type SetModeParams struct {
	SessionID string `json:"sessionId"`
	Mode      string `json:"mode"`
}

type SetModelParams

type SetModelParams struct {
	SessionID string `json:"sessionId"`
	Model     string `json:"model"`
	Effort    string `json:"effort,omitempty"`
}

type SetModelResult

type SetModelResult struct {
	Label string `json:"label"`
}

type SetRagScopeParams

type SetRagScopeParams struct {
	SessionID string `json:"sessionId"`
	Scope     string `json:"scope"`
}

type SetSessionPathParams

type SetSessionPathParams struct {
	SessionID   string `json:"sessionId"`
	SessionPath string `json:"sessionPath"`
}

type SetToolApprovalModeParams

type SetToolApprovalModeParams struct {
	SessionID string `json:"sessionId"`
	Mode      string `json:"mode"`
}

type SteerParams

type SteerParams struct {
	SessionID string `json:"sessionId"`
	Text      string `json:"text"`
}

type SubmitParams

type SubmitParams struct {
	SessionID string `json:"sessionId"`
	Input     string `json:"input"`
	Display   string `json:"display,omitempty"`
}

type SummarizeParams

type SummarizeParams struct {
	SessionID string `json:"sessionId"`
	Turn      int    `json:"turn"`
	UpTo      bool   `json:"upTo"`
}

type SwitchBranchParams

type SwitchBranchParams struct {
	SessionID string `json:"sessionId"`
	Ref       string `json:"ref"`
}

Jump to

Keyboard shortcuts

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