Documentation
¶
Overview ¶
Package orcaterm is the terminal half of chat delivery (cli#907, C1): the bounded `orca` runner, the four terminal calls delivery may make, and the screen checks that decide whether a composer may be typed into.
It started as a copy of internal/teamrouter's orca.go and screen.go, corrected for plan r2's rulings rather than moved: the router keeps its own files, frozen, until phase 3 retires it (C6). The corrections are the #906 guards (hadron-server#1940's bounded, fail-closed call; #1976 and #1985's final recap and notice rules) and R2 (any draft that is not our own is held, including the Claude "stale draft" the router typed over).
Nothing here ever returns, logs or reports screen or draft text: verdicts carry a reason code, never the line that decided them.
Index ¶
Constants ¶
const ( CallTimeout = 90 * time.Second MinCallTimeout = 75 * time.Second // SubmitWait is the --wait-submit observation window, in seconds: long // enough for a turn to start, short enough to leave the call its margin. SubmitWait = 30 )
CallTimeout bounds one exec (hadron-server#1940: router.ts CALL_TIMEOUT_MS). A hung Orca costs one call, not the loop. It must stay at least MinCallTimeout: the longest legitimate call is a `terminal send --wait-submit`, whose wait stays under it (see SubmitWait).
const MaxSendTextBytes = 131_072 - 1
MaxSendTextBytes is the longest text Send can carry: it travels as one argv string (orca terminal send has no file or stdin input), and Linux caps one argument at MAX_ARG_STRLEN, 131,072 bytes with its NUL.
Variables ¶
var ErrOrca = errors.New("orca call failed")
ErrOrca is a failed or unparsable `orca` call. Its text is a code, never Orca's output.
Functions ¶
func Normalize ¶
Normalize removes every whitespace character, so a composer's wrapped rendering compares equal to the one-line text that was typed.
func PromptLineIsEmpty ¶
PromptLineIsEmpty is true only on positive proof the agent's prompt holds no typed text (#5473: tui-idle reports idle while a human is typing).
- claude: the box between the last two column-0 rules is a bare `❯` plus blank lines, and the ONE nonblank line below it is the mode footer. Orca blanks a composer's text in the tail and reports it as the screen's draft, so the box alone is no proof: ReadComposer judges the draft first, and a Claude empty composer rests on Orca reporting none.
- codex: the last column-0 `›` line shows the idle placeholder and every line below it is footer.
Anything unrecognized is NOT empty.
func ScreenAgentFamily ¶
ScreenAgentFamily is the agent family a rendered screen POSITIVELY shows, or "": a shell, or both families' chrome at once (hold, never guess).
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client makes the four terminal calls through a guarded runner.
func (*Client) ReadScreen ¶
ReadScreen is the terminal's rendered full-frame screen, or nil when unreadable.
func (*Client) Send ¶
Send types text into the terminal and submits it. An observed send (text plus Enter, no interrupt) retries once, with Orca's durable request id, only after an ambiguous transport failure, as Orca prescribes: the id is bound to the payload and the terminal process, so a retry re-issues, never re-types. Nothing else ever retries a send.
type Composer ¶
type Composer string
Composer is the verdict on the composer: may it be typed into? The non-empty values are S5's hold reasons (hadron-server#2021) where one applies.
const ( // ComposerEmpty: positively proven empty. The only state typed into. ComposerEmpty Composer = "empty" // ComposerOwn: it holds text that starts with our prefix, our own // leftover from an earlier send. The caller decides recovery. ComposerOwn Composer = "own-leftover" // ComposerDraft: it holds anything else, a human's text included. R2: // held, never cleared, never stored. ComposerDraft Composer = "draft" // ComposerQuestion: a question, menu or approval prompt has the screen. ComposerQuestion Composer = "question" // ComposerUnknown: no recognized composer at all, a shell included. ComposerUnknown Composer = "screen-unknown" )
func ReadComposer ¶
func ReadComposer(sc *Screen, family string, ownPrefixes ...string) (state Composer, leftover string)
ReadComposer judges the composer under R2. leftover is the composer's own text, returned only with ComposerOwn so the caller can compare it with what it is about to send; it must never be logged or reported. Text that opens with any of ownPrefixes is the deliverer's own.
Order matters. A draft is judged first and for BOTH families: the router let a Claude screen that proves the composer empty refute Orca's draft (#6736), and R2 inverts that. Any draft that is not ours holds, so a ghost draft now reaches a human through S5's stuck alarm instead of being typed over.
type Liveness ¶
type Liveness string
Liveness is what the window above the prompt proves.
type Receipt ¶
type Receipt struct {
// Accepted is Orca's input acceptance.
Accepted bool
// TurnStarted is the strong delivery evidence: the agent began a turn.
TurnStarted bool
Stages []string
// ErrCode is Orca's error code when not accepted.
ErrCode string
}
Receipt is what a send established. It carries Orca's stages and an error code, never the text sent.
type Runner ¶
Runner execs the `orca` CLI. argv starts at the verb ("terminal", "list", …): the binary is the runner's business, so a fake never sees it.
func Exec ¶
Exec is the production runner. A call is killed with SIGKILL at the bound (exec.CommandContext's default Cancel is Process.Kill), and ANY failure other than an ordinary non-zero exit — the bound, a missing binary, a pipe error — reads as code 1 with EMPTY stdout: output a failure invalidated must never reach a caller that acts on it (#1940 cycles 1 and 2).
type Screen ¶
Screen is one `orca terminal read --screen` result: the rendered tail, the optional draft field, and the source (only "screen" is a full frame). Draft is held only to be tested; it is never logged or reported.
type SendOptions ¶
type SendOptions struct {
// Interrupt sends as interrupt-style input. Only a batch that says so
// (a halt, S6) sets it.
Interrupt bool
// EnterOnly submits what the composer already holds: no text is typed.
EnterOnly bool
// NoEnter types text without submitting it: a family's clearing
// keystroke, never a message.
NoEnter bool
}
SendOptions shape one send.
type Terminal ¶
type Terminal struct {
Handle string `json:"handle"`
WorktreePath string `json:"worktreePath"`
AgentIdentity *string `json:"agentIdentity"`
Connected bool `json:"connected"`
Writable bool `json:"writable"`
}
Terminal is one `orca terminal list` row.
func (*Terminal) UnmarshalJSON ¶
UnmarshalJSON reads Orca's row with router.ts's defaults: connected and writable count unless explicitly false.