tun-poc-proto

moon add tonyfettes/tun-poc-proto@0.3.3
Download zip
Version
0.3.3
License
Apache-2.0
Last updated
16 days ago
Downloads
165

Dependencies

README

#tun-poc-proto

Shared wire protocol types for tun-poc. Imported by the browser client, the relay, and the server agent so all three stay in sync.

Covers:

  • Relay ↔ client and relay ↔ server messages (task lifecycle, terminal I/O, render viewports, replay, reconnection).
  • REST API payloads (auth, user status, task list, machines, groups, and administration).
  • Codex JSON-RPC envelopes and filesystem event types.
  • Task UUIDs, machine/group/user payloads, and typed JSON codecs for each message variant.

See docs/protocol.md for the message flow.

#
AddMemberRequest

pub(all) struct AddMemberRequest {
login : String
}

#
Capability

pub(all) enum Capability {
RenderFrameVt
RenderFrameState
ViewportResize
ServerScrollback
ClientAttachAck
MoonIdeHover
FilesystemWatch
Unknown(String)
} derive(Eq,
Debug
)

#
Capability::from_wire

fn Capability::from_wire(value : String) -> Capability

#
Capability::to_wire

fn Capability::to_wire(self : Capability) -> String

#
CapabilitySet

pub struct CapabilitySet(Array[Capability]) derive(Eq,
Debug
)

#
CapabilitySet::empty

#
CapabilitySet::from_wire

fn CapabilitySet::from_wire(values : Array[String]) -> CapabilitySet

#
CapabilitySet::length

fn CapabilitySet::length(self : CapabilitySet) -> Int

#
CapabilitySet::new

#
CapabilitySet::supports

fn CapabilitySet::supports(self : CapabilitySet, capability : Capability) -> Bool

#
CapabilitySet::supports_client_attach_ack

fn CapabilitySet::supports_client_attach_ack(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_filesystem_watch

fn CapabilitySet::supports_filesystem_watch(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_moon_ide_hover

fn CapabilitySet::supports_moon_ide_hover(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_render_frame_state

fn CapabilitySet::supports_render_frame_state(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_render_frame_vt

fn CapabilitySet::supports_render_frame_vt(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_server_scrollback

fn CapabilitySet::supports_server_scrollback(self : CapabilitySet) -> Bool

#
CapabilitySet::supports_viewport_resize

fn CapabilitySet::supports_viewport_resize(self : CapabilitySet) -> Bool

#
CapabilitySet::to_log_string

fn CapabilitySet::to_log_string(self : CapabilitySet) -> String

#
CapabilitySet::to_wire

fn CapabilitySet::to_wire(self : CapabilitySet) -> Array[String]

#
CodexActiveFlag

pub(all) enum CodexActiveFlag {
WaitingOnApproval
WaitingOnUserInput
} derive(Eq,
Debug
)

#
CodexActivityStatus

pub(all) enum CodexActivityStatus {
NotLoaded
Idle
Active(Array[CodexActiveFlag])
SystemError
} derive(Eq,
Debug
)

#
CodexApproval

pub(all) enum CodexApproval {
Command(command~ : String)
FileChange(reason~ : String)
}

#
CodexApprovalDecision

pub(all) enum CodexApprovalDecision {
Accept
Decline
}

#
CodexClientInfo

pub(all) struct CodexClientInfo {
name : String
title : String
version : String
}

#
CodexIncoming

pub(all) enum CodexIncoming {
ThreadResult(thread~ : CodexThreadResult)
ThreadListResult(threads~ : Array[CodexThreadResult])
ThreadReadResult(thread~ : CodexThreadResult, turns~ : Array[CodexReadTurn])
OtherResponse(id~ : Json)
TurnStarted(turn_id~ : CodexTurnId)
TurnCompleted(turn_id~ : CodexTurnId, status~ : CodexStatus)
ItemStarted(turn_id~ : CodexTurnId, item_id~ : CodexItemId, kind~ : CodexItemKind, text~ : String, command~ : String)
ItemCompleted(turn_id~ : CodexTurnId, item_id~ : CodexItemId, status~ : CodexStatus)
Delta(turn_id~ : CodexTurnId, item_id~ : CodexItemId, delta~ : String, kind~ : CodexItemKind)
ThreadStatusChanged(thread_id~ : CodexThreadId, activity~ : CodexActivityStatus)
Approval(id~ : CodexRequestId, thread_id~ : CodexThreadId, turn_id~ : CodexTurnId, item_id~ : CodexItemId, approval~ : CodexApproval)
}

#
CodexItemId

pub(all) struct CodexItemId(String) derive(Eq,
Debug
)

#
CodexItemKind

pub(all) enum CodexItemKind {
AgentMessage
UserMessage
CommandExecution
FileChange
Reasoning
} derive(Eq,
Debug
)

#
CodexOutgoing

pub(all) enum CodexOutgoing {
Initialize(id~ : Int, client_info~ : CodexClientInfo)
ThreadStart(id~ : Int, cwd~ : String)
ThreadList(id~ : Int, cwd~ : String)
ThreadRead(id~ : Int, thread_id~ : CodexThreadId, include_turns~ : Bool)
ThreadResume(id~ : Int, thread_id~ : CodexThreadId)
TurnStart(id~ : Int, thread_id~ : CodexThreadId, input~ : String)
TurnInterrupt(id~ : Int, thread_id~ : CodexThreadId, turn_id~ : CodexTurnId)
Initialized
Approval(id~ : CodexRequestId, decision~ : CodexApprovalDecision)
}

#
CodexReadItem

pub(all) struct CodexReadItem {
id : CodexItemId
kind : CodexItemKind
text : String
command : String
output : String
}

#
CodexReadTurn

pub(all) struct CodexReadTurn {
id : CodexTurnId
items : Array[CodexReadItem]
status : CodexStatus
}

#
CodexRequestId

pub(all) struct CodexRequestId(Json)

#
CodexStatus

pub(all) enum CodexStatus {
InProgress
Completed
Failed
} derive(Eq,
Debug
)

#
CodexThreadResult

pub(all) struct CodexThreadResult {
id : CodexThreadId
preview : String
status : CodexThreadStatus
activity : CodexActivityStatus
} derive(Eq,
Debug
)

#
CodexThreadStatus

pub(all) enum CodexThreadStatus {
Open
Archived
Closed
} derive(Eq,
Debug
)

#
CodexTurnId

pub(all) struct CodexTurnId(String) derive(Eq,
Debug
)

#
CreateGroupRequest

pub(all) struct CreateGroupRequest {
name : String
}

#
CreateMachineRequest

pub(all) struct CreateMachineRequest {
name : String
}

#
CreateMachineResponse

pub(all) struct CreateMachineResponse {
token : String
machine_id : Int
}

#
CreatedGroupResponse

pub(all) struct CreatedGroupResponse {
id : Int
}

#
Cursor

pub(all) struct Cursor {
x : Int
y : Int
shape : CursorShape
blink : Bool
color : String?
} derive(Eq,
Debug
)

The visible cursor. Coordinates are zero-based viewport cells; a cursor on a wide glyph's trailing cell is already snapped to the glyph head. color is set only when the child application overrides the cursor color, so the client theme keeps the default. The glyph under a block cursor, its cell span, and its inverted color are not on the wire: the client derives them from the run grid it already holds.
impl ToJson for Cursor

#
CursorShape

pub(all) enum CursorShape {
Block
Bar
Underline
} derive(Eq,
Debug
)

#
DeviceApproveRequest

pub(all) struct DeviceApproveRequest {
code : String
}

Request body of POST /device/approve. Sent by the SPA when the user clicks Approve on the pairing page.

#
DeviceAuthorizationRequest

pub(all) struct DeviceAuthorizationRequest {
hostname : String
}

#
DeviceAuthorizationResponse

pub(all) struct DeviceAuthorizationResponse {
device_code : String
user_code : String
verification_uri : String
verification_uri_complete : String?
expires_in : Int
interval : Int
}

#
DeviceDenyRequest

pub(all) struct DeviceDenyRequest {
code : String
}

Request body of POST /device/deny. Sent by the SPA when the user clicks Deny on the pairing page.

#
DevicePendingResponse

pub(all) struct DevicePendingResponse {
hostname : String
}

Response body of GET /device/pending?code=<user_code>. Returned to the SPA approval page so it can render the hostname the agent reported.

#
DeviceTokenError

pub(all) enum DeviceTokenError {
AuthorizationPending
SlowDown
ExpiredToken
AccessDenied
InvalidRequest
UnsupportedGrantType
Unknown(String)
}

RFC 8628 §3.5 token-endpoint error codes, plus Unknown(String) as a forward-compatibility hatch for codes added by a future relay against an older server. Wire format is a bare JSON string (see DeviceTokenResponse::Error).

#
DeviceTokenRequest

pub(all) struct DeviceTokenRequest {
grant_type : String
device_code : String
}

#
DeviceTokenResponse

pub(all) enum DeviceTokenResponse {
Success(access_token~ : String, token_type~ : String)
Error(error~ : DeviceTokenError)
}

RFC 8628 §3.5 token-endpoint response. Discriminated on the wire by which field is present: access_token → Success, error → Error.

#
ErrorCode

pub(all) enum ErrorCode {
TaskNotFound
TaskOffline
InternalError
ProtoVersionTooOld(min_version~ : Int)
} derive(Eq,
Debug
)

#
ErrorCode::to_wire

fn ErrorCode::to_wire(self : ErrorCode) -> String

#
FileStat

pub(all) struct FileStat {
file_type : Int
size : Int64
mtime : Int64
ctime : Int64
} derive(
Debug
)

impl ToJson for FileStat

#
FileStat::to_log_string

fn FileStat::to_log_string(self : FileStat) -> String

#
Frame

pub(all) struct Frame {
full : Bool
styles : Array[RunStyle]
lines : Array[Line]
cursor : Cursor?
} derive(Eq,
Debug
)

Structured render payload for render_frame_state clients. The server diffs terminal state against what each client already holds, so lines carries only the rows to repaint unless full is set. Runs keep explicit col and width so the client can map text back to grid cells for selection without replaying a terminal emulator.

#
FsMessage

pub(all) enum FsMessage {
WatchFile(req_id~ : String, client_id~ : String, path~ : String)
UnwatchFile(req_id~ : String, client_id~ : String)
WatchFileReady(req_id~ : String, client_id~ : String, path~ : String, resolved_path~ : String)
FileChanged(req_id~ : String, client_id~ : String, path~ : String, resolved_path~ : String)
Stat(req_id~ : String, client_id~ : String, path~ : String)
StatResult(req_id~ : String, client_id~ : String, stat~ : FileStat)
Readdir(req_id~ : String, client_id~ : String, path~ : String)
ReaddirResult(req_id~ : String, client_id~ : String, entries~ : Array[(String, Int)])
ReadFile(req_id~ : String, client_id~ : String, path~ : String)
ReadFileResult(req_id~ : String, client_id~ : String, data~ : String)
WriteFile(req_id~ : String, client_id~ : String, path~ : String, data~ : String, create~ : Bool, overwrite~ : Bool)
Mkdir(req_id~ : String, client_id~ : String, path~ : String)
FsDelete(req_id~ : String, client_id~ : String, path~ : String, recursive~ : Bool)
FsRename(req_id~ : String, client_id~ : String, from~ : String, to~ : String, overwrite~ : Bool)
FsOk(req_id~ : String, client_id~ : String)
FsError(req_id~ : String, client_id~ : String, code~ : String, message~ : String)
} derive(
Debug
)

impl ToJson for FsMessage

#
FsMessage::client_id

fn FsMessage::client_id(self : FsMessage) -> String

#
FsMessage::to_log_string

fn FsMessage::to_log_string(self : FsMessage) -> String

#
GrantAccessRequest

pub(all) struct GrantAccessRequest {
group_id : Int
}

#
GroupInfo

pub(all) struct GroupInfo {
id : Int
name : String
owner_id : Int64
}

#
GroupMember

pub(all) struct GroupMember {
github_id : Int64
login : String
avatar_url : String
}

#
IdeErrorCode

pub(all) enum IdeErrorCode {
InvalidRequest
MoonUnavailable
MoonIdeFailed
IdeTimeout
} derive(Eq,
Debug
)

Fixed error classifications for the Moon IDE hover channel.

#
IdeErrorCode::from_wire

fn IdeErrorCode::from_wire(value : String) -> IdeErrorCode?

#
IdeErrorCode::to_wire

fn IdeErrorCode::to_wire(self : IdeErrorCode) -> String

#
IdeMessage

pub(all) enum IdeMessage {
Hover(req_id~ : String, client_id~ : String, path~ : String, line~ : Int, column~ : Int)
CancelHover(req_id~ : String, client_id~ : String)
HoverResult(req_id~ : String, client_id~ : String, path~ : String, range~ : String?, contents~ : Array[String])
IdeError(req_id~ : String, client_id~ : String, path~ : String, code~ : IdeErrorCode, message~ : String)
} derive(
Debug
)

Moon IDE hover messages. Positions and compact ranges use one-based Unicode code-point coordinates, matching moon ide hover.

#
IdeMessage::client_id

fn IdeMessage::client_id(self : IdeMessage) -> String

#
IdeMessage::to_log_string

fn IdeMessage::to_log_string(self : IdeMessage) -> String

#
Line

pub(all) struct Line {
y : Int
runs : Array[Run]
} derive(Eq,
Debug
)

#
MachineAccessGroup

pub(all) struct MachineAccessGroup {
group_id : Int
name : String
}

#
Message

pub(all) enum Message {
Sys(SysMessage)
Fs(FsMessage)
Ide(IdeMessage)
Term(TermMessage)
Codex(client_id~ : String, data~ : String)
} derive(
Debug
)

impl ToJson for Message

#
Message::client_id

fn Message::client_id(self : Message) -> String

#
Message::to_log_string

fn Message::to_log_string(self : Message) -> String

#
RegisterRejectReason

pub(all) enum RegisterRejectReason {
UuidAlreadyClaimedThisSession
InvalidUuid
ProtoVersionTooOld(min_version~ : Int)
} derive(Eq,
Debug
)

#
RegisterRejectReason::to_wire

fn RegisterRejectReason::to_wire(self : RegisterRejectReason) -> String

#
Run

pub(all) struct Run {
col : Int
width : Int
text : String
style : Int?
} derive(Eq,
Debug
)

One styled run of cells. An ASCII run holds one cell per character, so width equals the character count. A non-ASCII glyph always forms its own run whose width (1 or 2) is its grid-cell span; the client renders it as a fixed-width centered span so glyph advances cannot push later columns off the grid.
impl ToJson for Run

#
RunStyle

pub(all) struct RunStyle {
fg : String?
bg : String?
underline_color : String?
flags : Int
} derive(Eq,
Debug
)

Colors are #rrggbb; None means the client's default foreground or background. The server resolves palette indices (including bold promotion) but never substitutes its own default colors, so client themes keep owning the defaults — including under inverse, which the client applies by swapping resolved colors with its theme defaults.
impl ToJson for RunStyle
fn RunStyle::blink(self : RunStyle) -> Bool

#
RunStyle::bold

fn RunStyle::bold(self : RunStyle) -> Bool

#
RunStyle::conceal

fn RunStyle::conceal(self : RunStyle) -> Bool

#
RunStyle::faint

fn RunStyle::faint(self : RunStyle) -> Bool

#
RunStyle::inverse

fn RunStyle::inverse(self : RunStyle) -> Bool

#
RunStyle::is_default

fn RunStyle::is_default(self : RunStyle) -> Bool

Whether this is the default style a Run encodes as style : None.

#
RunStyle::italic

fn RunStyle::italic(self : RunStyle) -> Bool

#
RunStyle::new

fn RunStyle::new(fg? : String, bg? : String, underline_color? : String, bold? : Bool, faint? : Bool, italic? : Bool, strikethrough? : Bool, overline? : Bool, blink? : Bool, inverse? : Bool, conceal? : Bool, underline? : Underline) -> RunStyle

#
RunStyle::overline

fn RunStyle::overline(self : RunStyle) -> Bool

#
RunStyle::strikethrough

fn RunStyle::strikethrough(self : RunStyle) -> Bool

#
RunStyle::underline

fn RunStyle::underline(self : RunStyle) -> Underline

#
SysMessage

pub(all) enum SysMessage {
Register(task_uuid~ :
UUID
, hostname~ : String, cwd~ : String, proto_version~ : Int, server_capabilities~ : CapabilitySet)
Registered(task_uuid~ :
UUID
)
RegisterRejected(reason~ : RegisterRejectReason)
TaskExited(exit_code~ : Int)
Title(title~ : String?)
Connect(task_uuid~ :
UUID
, last_seen_id~ : Int64?, proto_version~ : Int, client_capabilities~ : CapabilitySet)
Connected(server_proto_version~ : Int, server_capabilities~ : CapabilitySet)
TaskOnline(server_proto_version~ : Int, server_capabilities~ : CapabilitySet)
NewClient(client_id~ : String, last_seen_id~ : Int64?, client_proto_version~ : Int, client_capabilities~ : CapabilitySet)
ClientDisconnected(client_id~ : String)
Error(ErrorCode)
AuthError(message~ : String)
}

impl Debug for SysMessage

#
SysMessage::client_id

fn SysMessage::client_id(self : SysMessage) -> String

#
SysMessage::to_log_string

fn SysMessage::to_log_string(self : SysMessage) -> String

#
TaskEntry

pub(all) struct TaskEntry {
task_uuid :
UUID

machine_id : Int
hostname : String
cwd : String
title : String?
owner : String
online : Bool
last_seen_at : Int64
} derive(Eq)

Flat row for the GET /api/tasks listing. One row per running task instance (keyed by task_uuid), joined with its parent machine's display info. machine_id groups tasks that belong to the same long-lived machine; task_uuid is the identity used everywhere else on the wire.
impl ToJson for TaskEntry

#
TermMessage

pub(all) enum TermMessage {
ClientReplayCursor(client_id~ : String, last_seen_id~ : Int64?)
Viewport(client_id~ : String, cols~ : Int, rows~ : Int, active~ : Bool)
RenderFrame(client_id~ : String, seq~ : Int64, cols~ : Int, rows~ : Int, scroll_offset~ : Int64, scrollback_rows~ : Int64, title~ : String?, mouse~ : Bool?, data~ : String)
RenderState(client_id~ : String, seq~ : Int64, cols~ : Int, rows~ : Int, scroll_offset~ : Int64, scrollback_rows~ : Int64, title~ : String?, mouse~ : Bool?, frame~ : Frame)
InputText(client_id~ : String, text~ : String)
InputKey(client_id~ : String, key~ : String, mods~ : Array[String], text~ : String?)
InputPaste(client_id~ : String, text~ : String)
InputMouse(client_id~ : String, x~ : Int, y~ : Int, button~ : String?, action~ : String, mods~ : Array[String])
InputScroll(client_id~ : String, x~ : Int, y~ : Int, delta_rows~ : Int, mods~ : Array[String])
ScrollToLive(client_id~ : String)
Theme(client_id~ : String, background~ : String, foreground~ : String)
Data(client_id~ : String, id~ : Int64, created~ : Int64?, replay~ : Bool?, data~ : String)
Exited(client_id~ : String, id~ : Int64)
} derive(
Debug
)

#
TermMessage::client_id

fn TermMessage::client_id(self : TermMessage) -> String

#
TermMessage::to_log_string

fn TermMessage::to_log_string(self : TermMessage) -> String

#
TransferGroupRequest

pub(all) struct TransferGroupRequest {
new_owner_id : Int64
}

#
Underline

pub(all) enum Underline {
None
Single
Double
Curly
Dotted
Dashed
} derive(Eq,
Debug
)

#
UserInfo

pub(all) struct UserInfo {
github_id : Int64
login : String
avatar_url : String
status : UserStatus
is_admin : Bool
} derive(Eq)

#
UserStatus

pub(all) enum UserStatus {
Pending
Approved
Rejected
} derive(Eq,
Debug
)

#
UserStatus::from_string

fn UserStatus::from_string(s : String) -> UserStatus

#
UserStatus::to_string

fn UserStatus::to_string(self : UserStatus) -> String

#
ProtoMinVersion

let ProtoMinVersion : Int

Lowest proto_version the relay accepts on Register/Connect. Bump to match ProtoVersion when dropping support for a prior version.

#
ProtoVersion

let ProtoVersion : Int

Wire protocol version this build speaks. Bumped when peers need to reason about a new protocol capability or when a breaking Register/Connect/sys-channel handshake change lands. Optional version fields default to 0 so peers built before versioning was introduced decode as version 0 — fully backwards compatible.