tunnel

package
v1.3.9 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventConnected          = "connected"
	EventSessionInfo        = "session_info"
	EventUserMessage        = "user_message" // user text from desktop
	EventText               = "text"         // streaming text chunk
	EventTextDone           = "text_done"    // text stream complete
	EventStatus             = "status"       // agent status change
	EventToolCall           = "tool_call"
	EventToolResult         = "tool_result"
	EventApprovalRequest    = "approval_request"
	EventApprovalResult     = "approval_result"
	EventAskUserRequest     = "ask_user_request"
	EventAskUserResponse    = "ask_user_response"
	EventSubagentSpawn      = "subagent_spawn"
	EventSubagentText       = "subagent_text"
	EventSubagentStatus     = "subagent_status"
	EventSubagentToolCall   = "subagent_tool_call"
	EventSubagentToolResult = "subagent_tool_result"
	EventSubagentComplete   = "subagent_complete"
	EventError              = "error"
	EventPing               = "ping"
	EventDisconnected       = "disconnected"
)

Server → Client event types.

View Source
const (
	EventAck            = "ack" // client ACK for sequenced delivery
	CmdMessage          = "message"
	CmdApprovalResponse = "approval_response"
	CmdInterrupt        = "interrupt"
	CmdModeChange       = "mode_change"
	CmdAskUserResponse  = "ask_user_response"
	CmdPong             = "pong"
)

Client → Server command types.

View Source
const (
	StatusIdle     = "idle"
	StatusThinking = "thinking"
	StatusRunning  = "running"
	StatusWaiting  = "waiting" // waiting for approval
	StatusError    = "error"
)

Agent status values.

View Source
const (
	ModeSupervised = "supervised"
	ModeAuto       = "auto"
	ModeBypass     = "bypass"
	ModeAutopilot  = "autopilot"
)

Mode values.

View Source
const (
	DecisionAllow       = "allow"
	DecisionDeny        = "deny"
	DecisionAlwaysAllow = "always_allow"
)

Approval decisions.

View Source
const DefaultRelayURL = "wss://gateway.ggcode.dev"

DefaultRelayURL is the default ggcode-relay server URL.

Variables

This section is empty.

Functions

func QRCodeForURL

func QRCodeForURL(url string) (string, error)

QRCodeForURL generates a QR code string for the given URL using terminal-friendly block characters. Returns a string that can be printed directly to a terminal.

func QRCodeLines

func QRCodeLines(url string) ([]string, error)

QRCodeLines returns the QR code as a slice of strings (one per line).

func QRCodePNG

func QRCodePNG(url string) ([]byte, error)

QRCodePNG generates a PNG image of the QR code for the given URL. Returns raw PNG bytes suitable for displaying in an image widget.

Types

type ApprovalRequestData

type ApprovalRequestData struct {
	ID       string `json:"id"`
	ToolName string `json:"tool_name"`
	Input    string `json:"input"`
}

ApprovalRequestData carries an approval request to the mobile client.

type ApprovalResponseData

type ApprovalResponseData struct {
	ID       string `json:"id"`
	Decision string `json:"decision"` // allow/deny/always_allow
}

ApprovalResponseData carries the user's approval decision back.

type AskUserAnswer

type AskUserAnswer struct {
	QuestionID   string   `json:"question_id"`
	ChoiceIDs    []string `json:"choice_ids,omitempty"`
	FreeformText string   `json:"freeform_text,omitempty"`
}

AskUserAnswer carries a single question answer.

type AskUserChoice

type AskUserChoice struct {
	ID    string `json:"id"`
	Label string `json:"label"`
}

AskUserChoice represents a selectable choice.

type AskUserQuestion

type AskUserQuestion struct {
	ID            string          `json:"id"`
	Prompt        string          `json:"prompt"`
	Kind          string          `json:"kind"` // single/multi/text
	Choices       []AskUserChoice `json:"choices,omitempty"`
	AllowFreeform bool            `json:"allow_freeform,omitempty"`
	Placeholder   string          `json:"placeholder,omitempty"`
}

AskUserQuestion represents a single question in the questionnaire.

type AskUserRequestData

type AskUserRequestData struct {
	ID        string            `json:"id"`
	Title     string            `json:"title,omitempty"`
	Questions []AskUserQuestion `json:"questions"`
}

AskUserRequestData carries a structured questionnaire from the agent. This is NOT the same as approval_request — it's a multi-question form with single/multi/text question types.

type AskUserResponseData

type AskUserResponseData struct {
	ID      string          `json:"id"`
	Status  string          `json:"status"` // submitted/cancelled
	Answers []AskUserAnswer `json:"answers,omitempty"`
}

AskUserResponseData carries the user's answers back.

type Broker

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

Broker bridges agent events and the WebSocket tunnel protocol.

Delivery guarantees:

  • Text chunks are batched: PushText appends to a per-msgID buffer; a 300ms ticker flushes all accumulated text as a single message.
  • Every outbound message carries a monotonically-increasing Seq.
  • A sender goroutine sends one message at a time and waits for the mobile client to ACK (by seq) before sending the next.
  • If ACK times out (5s), the next message is sent anyway.
  • ReplayToClient bypasses ACK flow control for fast reconnect.

func NewBroker

func NewBroker(sess *Session) *Broker

func (*Broker) NextMessageID

func (b *Broker) NextMessageID() string

func (*Broker) OnClientConnect

func (b *Broker) OnClientConnect(fn func())

func (*Broker) OnCommand

func (b *Broker) OnCommand(fn func(cmd GatewayMessage))

func (*Broker) PushApprovalRequest

func (b *Broker) PushApprovalRequest(id, toolName, input string)

func (*Broker) PushApprovalResult

func (b *Broker) PushApprovalResult(id, decision string)

func (*Broker) PushAskUserRequest

func (b *Broker) PushAskUserRequest(id, title string, questions []AskUserQuestion)

func (*Broker) PushAskUserResponse

func (b *Broker) PushAskUserResponse(id, status string, answers []AskUserAnswer)

func (*Broker) PushChatClear

func (b *Broker) PushChatClear()

func (*Broker) PushChatHistory

func (b *Broker) PushChatHistory(messages []HistoryEntry)

func (*Broker) PushError

func (b *Broker) PushError(message string)

func (*Broker) PushSharingStopped

func (b *Broker) PushSharingStopped()

func (*Broker) PushStatus

func (b *Broker) PushStatus(status, message string)

func (*Broker) PushSubagentComplete

func (b *Broker) PushSubagentComplete(agentID, name, summary string, success bool)

func (*Broker) PushSubagentSpawn

func (b *Broker) PushSubagentSpawn(agentID, name, task, color, parentID string)

func (*Broker) PushSubagentStatus

func (b *Broker) PushSubagentStatus(agentID, status, message string)

func (*Broker) PushSubagentText

func (b *Broker) PushSubagentText(agentID, msgID, chunk string, done bool)

func (*Broker) PushSubagentToolCall

func (b *Broker) PushSubagentToolCall(agentID, toolID, toolName, args, detail string)

func (*Broker) PushSubagentToolResult

func (b *Broker) PushSubagentToolResult(agentID, toolID, toolName, result string, isError bool)

func (*Broker) PushText

func (b *Broker) PushText(id, chunk string)

func (*Broker) PushTextDone

func (b *Broker) PushTextDone(id string)

func (*Broker) PushToolCall

func (b *Broker) PushToolCall(toolID, toolName, args, detail string)

func (*Broker) PushToolResult

func (b *Broker) PushToolResult(toolID, toolName, result string, isError bool)

func (*Broker) PushUserMessage

func (b *Broker) PushUserMessage(text string)

func (*Broker) ReplayToClient

func (b *Broker) ReplayToClient()

ReplayToClient resends all logged messages, bypassing ACK flow control.

func (*Broker) SendSessionInfo

func (b *Broker) SendSessionInfo(data SessionInfoData)

func (*Broker) Stop

func (b *Broker) Stop()

type Crypto

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

Crypto provides AES-GCM encryption/decryption using the token as key.

func NewCrypto

func NewCrypto(tokenHex string) (*Crypto, error)

NewCrypto creates a Crypto instance from a hex-encoded token (32+ hex chars = 16+ byte key). The token hex string is decoded to bytes and used directly as AES-128/256 key.

func (*Crypto) Decrypt

func (c *Crypto) Decrypt(nonceB64, ciphertextB64 string) ([]byte, error)

Decrypt decrypts base64-encoded nonce + ciphertext and returns plaintext.

func (*Crypto) Encrypt

func (c *Crypto) Encrypt(plaintext []byte) (nonce string, ciphertext string, err error)

Encrypt encrypts plaintext and returns (nonce_base64, ciphertext_base64).

type ErrorData

type ErrorData struct {
	Message string `json:"message"`
	Code    string `json:"code,omitempty"`
}

ErrorData carries an error.

type GatewayMessage

type GatewayMessage struct {
	Seq  int64           `json:"seq,omitempty"`
	Type string          `json:"type"`
	Data json.RawMessage `json:"data,omitempty"`
}

GatewayMessage is a JSON message exchanged over the encrypted channel.

type HistoryEntry

type HistoryEntry struct {
	Role    string `json:"role"`
	Content string `json:"content"`
	// Tool fields (role == "tool_call" or "tool_result")
	ToolID   string `json:"tool_id,omitempty"`
	ToolName string `json:"tool_name,omitempty"`
	ToolArgs string `json:"tool_args,omitempty"`
	Result   string `json:"result,omitempty"`
	IsError  bool   `json:"is_error,omitempty"`
}

type MessageData

type MessageData struct {
	Text string `json:"text"`
}

MessageData carries a user message.

type ModeChangeData

type ModeChangeData struct {
	Mode string `json:"mode"`
}

ModeChangeData carries a mode change request.

type RelayClient

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

RelayClient connects to the ggcode-relay server as the "server" role. It auto-reconnects on disconnect with exponential backoff.

func NewRelayClient

func NewRelayClient(relayURL, token string) (*RelayClient, error)

func (*RelayClient) Close

func (rc *RelayClient) Close()

func (*RelayClient) Connect

func (rc *RelayClient) Connect() error

Connect starts the connection loop. It connects, runs pumps, and auto-reconnects.

func (*RelayClient) ConnectURL

func (rc *RelayClient) ConnectURL() string

func (*RelayClient) OnConnect

func (rc *RelayClient) OnConnect(fn func())

func (*RelayClient) OnMessage

func (rc *RelayClient) OnMessage(fn func(msg GatewayMessage))

func (*RelayClient) Send

func (rc *RelayClient) Send(msg GatewayMessage) error

Send encrypts and sends a GatewayMessage to the relay. Safe to call after Close — returns error instead of panicking.

func (*RelayClient) Token

func (rc *RelayClient) Token() string

type Session

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

Session manages a relay session: connects to ggcode-relay, generates QR code.

Usage:

sess := tunnel.NewSession("wss://relay.ggcode.app")
info, err := sess.Start(ctx)
fmt.Println(info.ConnectURL)
fmt.Println(info.QRCode)
sess.Send(msg)
sess.OnMessage(func(m) { ... })
sess.Stop()

func NewSession

func NewSession(relayURL string) *Session

NewSession creates a new relay session.

func (*Session) Info

func (s *Session) Info() *SessionInfo

func (*Session) OnConnect

func (s *Session) OnConnect(fn func())

func (*Session) OnMessage

func (s *Session) OnMessage(fn func(msg GatewayMessage))

func (*Session) Send

func (s *Session) Send(msg GatewayMessage) error

func (*Session) Start

func (s *Session) Start(ctx context.Context) (*SessionInfo, error)

Start connects to the relay server and returns connection info.

func (*Session) Stop

func (s *Session) Stop()

type SessionInfo

type SessionInfo struct {
	ConnectURL string // wss://relay.ggcode.app/ws?role=client&token=abc123
	Token      string
	QRCode     string // terminal-friendly QR code (text)
	QRCodePNG  []byte // PNG image bytes for GUI display
	QRLines    []string
}

SessionInfo contains the connection details after a session starts.

type SessionInfoData

type SessionInfoData struct {
	Workspace string `json:"workspace"`
	Model     string `json:"model"`
	Provider  string `json:"provider"`
	Mode      string `json:"mode"`
	Version   string `json:"version"`
}

SessionInfoData carries session metadata sent after connection.

type StatusData

type StatusData struct {
	Status  string `json:"status"`
	Message string `json:"message,omitempty"`
}

StatusData carries an agent status change.

type SubagentCompleteData

type SubagentCompleteData struct {
	AgentID string `json:"agent_id"`
	Name    string `json:"name"`
	Summary string `json:"summary"` // one-line summary of what was done
	Success bool   `json:"success"`
}

SubagentCompleteData notifies that a sub-agent has finished.

type SubagentSpawnData

type SubagentSpawnData struct {
	AgentID  string `json:"agent_id"`
	Name     string `json:"name"`                // e.g. "Researcher", "Coder"
	Task     string `json:"task"`                // brief task description
	Color    string `json:"color,omitempty"`     // e.g. "#4CAF50"
	ParentID string `json:"parent_id,omitempty"` // empty for top-level
}

SubagentSpawnData notifies mobile that a sub-agent has been spawned. Mobile should show a live activity card for this agent.

type SubagentStatusData

type SubagentStatusData struct {
	AgentID string `json:"agent_id"`
	Status  string `json:"status"` // running/waiting_approval/completed/failed
	Message string `json:"message,omitempty"`
}

SubagentStatusData carries status updates for a sub-agent.

type SubagentTextData

type SubagentTextData struct {
	AgentID string `json:"agent_id"`
	ID      string `json:"id"` // message ID for grouping chunks
	Chunk   string `json:"chunk"`
	Done    bool   `json:"done"`
}

SubagentTextData carries streaming text from a sub-agent.

type SubagentToolCallData

type SubagentToolCallData struct {
	AgentID  string `json:"agent_id"`
	ToolID   string `json:"tool_id"`
	ToolName string `json:"tool_name"`
	Args     string `json:"args,omitempty"`
	Detail   string `json:"detail,omitempty"`
}

SubagentToolCallData carries tool call info from a sub-agent.

type SubagentToolResultData

type SubagentToolResultData struct {
	AgentID  string `json:"agent_id"`
	ToolID   string `json:"tool_id"`
	ToolName string `json:"tool_name"`
	Result   string `json:"result"`
	IsError  bool   `json:"is_error"`
}

SubagentToolResultData carries tool result from a sub-agent.

type TextData

type TextData struct {
	ID    string `json:"id"`    // message ID to group chunks
	Chunk string `json:"chunk"` // text content
	Done  bool   `json:"done"`  // true on last chunk
}

TextData carries a streaming text chunk.

type ToolCallData

type ToolCallData struct {
	ToolID   string `json:"tool_id"`
	ToolName string `json:"tool_name"`
	Args     string `json:"args,omitempty"`
	Detail   string `json:"detail,omitempty"`
}

ToolCallData carries a tool call notification.

type ToolResultData

type ToolResultData struct {
	ToolID   string `json:"tool_id"`
	ToolName string `json:"tool_name"`
	Result   string `json:"result,omitempty"`
	IsError  bool   `json:"is_error,omitempty"`
}

ToolResultData carries a tool result.

Jump to

Keyboard shortcuts

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