feat(server-mode): collaborators run sessions on their own account (sharing phase 2)
A user a workspace is shared with may now start and resume AI sessions in it. The run uses THEIR OWN account — a Claude pool setup-token, a Codex/Cursor pool API key, or an AI Proxy of theirs — never the owner's login or a pool login (409 ENOCOLLABACCOUNT otherwise). Their quota decides (EQUOTA, their own flag file, the sweep goes by payer). Money is per payer by UTC hour (session_payers, server/lib/session-payers.js): a session nobody else ran is billed as before; one a collaborator started is theirs; a resume changes hands from the next hour. Only Claude books by the hour, so a cross-payer resume of any other tool and a collaborator's resumeLast are refused (409 ECOLLABRESUME); a Terminal tab stays the owner's. Users page, details, quotas, Today (mine=1) and developer budgets count by payer. Docs: SERVER-MODE.md, API.md, CLAUDE.md, plan status.
This commit is contained in:
+9
-4
@@ -2110,10 +2110,15 @@ WHOLE list — at most 200 enabled users, never the owner (`400 EBADUSER`) — f
|
||||
owner or an admin only (`403 ENOTOWNER`), same-origin, each change audited. Local
|
||||
mode: `GET` answers an empty list, `PUT` `400 ELOCALMODE`. A user it is shared with
|
||||
sees and works in it like its owner, but `PATCH {title}`, `reset`/`remove`/`purge`,
|
||||
`DELETE` and `PUT …/shares` answer them `403 ENOTOWNER`, and a non-shell
|
||||
`POST /api/lanes/:id/start` or any `POST /api/run` `403 ECOLLABSTART`. A Terminal
|
||||
tab they open (`start {shell: true}`) records them in `dashboard_runs.started_by`:
|
||||
its pane token acts as them, not the owner. A user disabled since stays on the
|
||||
`DELETE` and `PUT …/shares` answer them `403 ENOTOWNER`. A session they start or
|
||||
resume (`POST /api/lanes/:id/start`, `POST /api/run`) runs on THEIR OWN account —
|
||||
a pool setup-token (Claude) or API key (Codex, Cursor) they may use, or an AI
|
||||
Proxy of theirs — else `409 ENOCOLLABACCOUNT`; resuming a non-Claude session the other side pays
|
||||
for, or a collaborator's `resumeLast`, is `409 ECOLLABRESUME`; their spend quota (`429 EQUOTA`)
|
||||
decides, not the owner's. Every pane they open (a Terminal tab too) records them
|
||||
in `dashboard_runs.started_by`: its pane token acts as them, and an AI pane's
|
||||
session hours are billed to them (`session_payers`; a Terminal tab's stay the
|
||||
owner's). A user disabled since stays on the
|
||||
list (`disabled: true`) and may be kept or removed; only a new one must be enabled. Users taken off
|
||||
get the WebSocket message `lane_access` `{laneId, userIds}` (sent to them only). See
|
||||
`docs/SERVER-MODE.md` → Sharing a workspace.
|
||||
|
||||
Reference in New Issue
Block a user