| 1 | // Package serve exposes a control.Controller over HTTP: the typed event stream |
| 2 | // as Server-Sent Events, and the commands as small JSON POST endpoints. It is a |
| 3 | // second frontend alongside the chat TUI — proof that the controller is |
| 4 | // transport-agnostic, and the basis for a browser/desktop client. A server has |
| 5 | // one foreground session and may finish switched-away sessions in background. |
| 6 | // |
| 7 | // # Session ownership |
| 8 | // |
| 9 | // A session has exactly one writer at a time — the runtime holding its lease. |
| 10 | // When the machine hosting Serve is also where the user now sits (the remote |
| 11 | // desktop came "home"), the local Reasonix window can take a session over: |
| 12 | // Serve releases the lease and the local window acquires it. Serve keeps no |
| 13 | // controller authority for a mirrored session, but stays the rendezvous: the |
| 14 | // remote tab's SSE stream keeps rendering because the local writer pushes its |
| 15 | // frames through POST /external/frames, and the remote side drops to read-only |
| 16 | // until it reclaims speaking rights via POST /reclaim. |
| 17 | // |
| 18 | // Every transition is cooperative — nothing ever steals the OS-level lease |
| 19 | // file lock. Handoff releases what Serve holds (session_handoff.go); reclaim |
| 20 | // waits for the local writer to release what it holds (session_reclaim.go), |
| 21 | // and a dead writer releases implicitly when the kernel drops its file lock. |
| 22 | package serve |
| 23 |