feat(server-mode): pane presence and typing audit (sharing phase 4)

A pane's tab shows the other people who have it open (pane-presence.js,
in memory, fed by the /ws-pty attach; GET /api/lanes/:id/presence and the
pane_presence broadcast to the owner and full collaborators) and says
"Billed to <name>" for a pane a collaborator opened (startedBy on the run).
The first real keystroke of each attach into a shared workspace's pane by
anyone but its owner is audited as `type into <run id>` (mouse, focus and
terminal replies to tmux do not count). The pty socket now pings, so a
vanished browser is ended at the next re-check and leaves the presence list.
This commit is contained in:
2026-11-06 11:32:25 +07:00
parent 879a6bb02d
commit 18e574a765
21 changed files with 568 additions and 8 deletions
+11
View File
@@ -2126,6 +2126,17 @@ answers only that workspace's reads, the workspace list (filtered to it), its
stage / up / down / hook / feature / mcp-sync writes and `/api/health`
(`403 EPANESCOPE` — never a start or resume).
```http
GET /api/lanes/:id/presence → { panes: { "<run id>": [{id, name}] } }
```
Who has which pane open (server mode; local mode `{panes: {}}`), in memory;
changes come as the WebSocket message `pane_presence` `{laneId, runId, users}`
to the workspace's owner and full collaborators. A run handle
(`GET /api/run`) carries `startedBy: {id, name}` when a collaborator opened
it — they pay for it. The first keystroke of a terminal attach into a shared
workspace's pane by anyone but its owner is audited (`type into <run id>`).
```http
GET /api/lanes/:id/sessions/:sid/shares → { shares, canManage }
PUT /api/lanes/:id/sessions/:sid/shares {"userIds": [3]} → { shares }