codai docs
Sesiuni partajate

Releul de host-uri

Rulează o comandă shell sau citește un fișier pe desktopul tău de pe telefon, dintr-un browser sau dintr-un script — fără SSH, fără port de intrare, doar în același cont.

Releul de host-uri permite oricărui client al tău să execute un vocabular mic și fix de operații pe unul dintre desktopurile tale care are aplicația codai desktop deschisă. Desktopul ține o conexiune SSE de ieșire către gateway și se anunță ca host; un solicitant face POST cu un exec și gateway-ul îl retransmite, apoi retransmite răspunsul înapoi. Nimic nu este persistat, nimic nu ascultă pe desktop și în v1 host-ul și solicitantul trebuie să aparțină aceluiași utilizator.

   telefon / browser / script               gateway                       desktop (host)
   ──────────────────────────             ─────────                      ───────────────
   POST /v1/hosts/:dev/exec  ───────▶  rendezvous după device id ─────▶  event: exec  (pe SSE-ul lui)
        { op, args }                                                       rulează op-ul local
   200 { ok, result }        ◀───────  rendezvous după req_id    ◀─────  POST /v1/hosts/exec/:reqId/result

Această suprafață este servită de https://ai.codai.ro și nu face parte din specificația publicată Shared Sessions v1; tratează-o ca remote sessions v1.

Ce desktopuri sunt online

curl https://ai.codai.ro/v1/hosts -H "Authorization: Bearer $CODAI_API_KEY"
{
  "hosts": [
    {
      "device_id": "1c2f…-uuid",
      "name": "Work laptop",
      "platform": "desktop",
      "os": "windows",
      "hostname": "DRAGOS-PC",
      "roots": ["E:\\gh\\codai", "C:\\Users\\dragos\\Documents"],
      "since": 1790160000000,
      "last_seen": 1790160045000
    }
  ]
}

Apar doar dispozitivele tale, cele văzute cel mai recent întâi. since și last_seen sunt milisecunde epoch; un host dispare din listă 45 de secunde după ultimul heartbeat. roots sunt directoarele pe care desktopul le va lăsa operațiile pe fișiere să le atingă.

Rulează ceva pe un host

POST /v1/hosts/:deviceId/exec — necesită cheia ta și un header x-codai-device care identifică solicitantul.

Proprietate

Tip

curl https://ai.codai.ro/v1/hosts/1c2f…/exec \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "x-codai-device: $(uuidgen)" -H "x-codai-device-platform: cli" \
  -H "Content-Type: application/json" \
  -d '{ "op": "shell", "args": { "cmd": "git status --short", "cwd": "E:\\gh\\codai" }, "timeout_ms": 30000, "label": "docs check" }'

Răspunsul — răspunsul host-ului, exact așa cum a venit:

{
  "req_id": "c0de…-uuid",
  "ok": true,
  "result": { "code": 0, "stdout": " M apps/docs/content/docs/en/sessions/hosts.mdx\n", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 },
  "error": null
}

Un eșec pe partea host-ului — o cale în afara roots, un argument greșit, o comandă care nu a putut porni — este tot HTTP 200 cu ok: false și error setat. Doar problemele releului sunt erori HTTP:

StatuscodeCând
400bad_requestx-codai-device lipsă, op necunoscut, timeout_ms în afara intervalului.
404not_founddeviceId nu este unul dintre dispozitivele tale (gateway-ul nu dezvăluie niciodată id-urile de dispozitiv ale altor utilizatori).
409host_offlineEste dispozitivul tău, dar nu este conectat ca host acum — open codai desktop.
504host_timeoutHost-ul nu a răspuns în timeout_ms — host did not answer within 30000 ms.

Operații

Desktopul implementează fiecare op cu propriile comenzi verificate de permisiuni; căile de fișiere trebuie să fie sub roots-urile host-ului.

opargsresult
shell{ cmd: string, cwd?: string, timeout_ms?: number } — PowerShell pe Windows, shell-ul de login în rest; timeout_ms este limitat la cel al request-ului.{ code, stdout, stderr, truncated, timed_out, duration_ms }
fs_read{ path: string, max_bytes?: integer } — implicit 64 KB, max 512 KB.{ path, content, size, truncated }
fs_write{ path: string, content: string }{ path, bytes, created }
fs_list{ path: string }{ path, entries: [{ name, kind, size }], truncated }
fs_roots{}{ roots: string[] }
info{}{ os: 'windows' | 'linux' | 'macos', hostname, roots, platform: 'desktop' }

shell rulează cu privilegiile utilizatorului de pe desktop. Releul nu adaugă niciun sandbox propriu — setarea de autonomie și regulile aplicației desktop decid ce va executa, și fiecare request apare în UI-ul ei cu label-ul tău. Ține cheile API care pot ajunge la /v1/hosts la fel de strict delimitate ca orice cheie SSH.

Construiește un host

Ai nevoie de această secțiune doar dacă îți scrii propriul host (aplicația codai desktop este deja unul).

Anunță-te

Deschide GET /v1/hosts/stream cu cheia ta și cu x-codai-device-ul propriu al host-ului. Descrie mașina în query string (un GET nu are body): ?os=windows&hostname=DRAGOS-PC&roots=E:\gh\codai,C:\Users\dragos\Documents — os ≤ 40 caractere, hostname ≤ 120, până la 32 de roots.

Primul frame este hello, apoi un ping la fiecare 15 s; fiecare ping îți reîmprospătează prezența (TTL 45 s). Serverul închide stream-ul după 6 ore — reconectează-te cu backoff (desktopul folosește 1 s → 30 s).

event: hello
data: {"device_id":"1c2f…","heartbeat_ms":15000}

event: ping
data: {"t":1790160045000}

event: exec
data: {"req_id":"c0de…","op":"shell","args":{"cmd":"git status --short","cwd":"E:\\gh\\codai"},"timeout_ms":30000,"label":"docs check","from_device_id":"9a0b…","ts":1790160050000}

Execută și răspunde

Pentru fiecare frame exec, rulează op-ul și fă POST /v1/hosts/exec/:reqId/result cu { "ok": boolean, "result"?: any, "error"?: string ≤ 4000 }. Body-ul trebuie să rămână sub 2 MB, iar reqId trebuie să fie UUID-ul de 36 de caractere pe care l-ai primit. Un răspuns lipsă sau întârziat lasă pur și simplu timeout_ms-ul solicitantului să expire.

curl -X POST https://ai.codai.ro/v1/hosts/exec/c0de…/result \
  -H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: 1c2f…" \
  -H "Content-Type: application/json" \
  -d '{ "ok": true, "result": { "code": 0, "stdout": "…", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 } }'

req_id este o capability imposibil de ghicit, dată doar ție; gateway-ul potrivește după ea răspunsul cu solicitantul care așteaptă și răspunde { "ok": true }.

Impune-ți propriile roots

Gateway-ul retransmite; tu decizi ce rulează. Refuză căile din afara roots-urilor anunțate, limitează timeout-urile shell la timeout_ms-ul request-ului, plafonează dimensiunile output-ului (setează truncated: true) și afișează fiecare request în UI-ul tău cu label-ul și from_device_id-ul lui.

Pe această pagină