Telepítés és kliensek
A Control Center nem egyetlen program. Vékonykliens-architektúra: egy headless szerver, amely az Ön adatait birtokolja, és kliensek egy csoportja, amelyek egyetlen, hozzá vezető RPC-kapcsolat fölött jelenítenek meg felületet. Ennek a kettéválasztásnak a megértése megmagyarázza, miért ott futnak a dolgok, ahol, és hogy az egyes kliensek mihez férnek hozzá és mihez nem.
Az adatokat a szerver birtokolja
Szekció neve “Az adatokat a szerver birtokolja”A cc_server nevű folyamat tartja az adatbázisokat — egy kicsi global.db-t
a szerver szintű állapothoz, valamint munkaterületenként
egy-egy SQLite-fájlt, amelyeket csak akkor nyit meg, amikor kell —, és a
hosszú életű munkát végzi: pipeline-motorok, összehangolók, az
MCP-eszközfelület és az orchestrációs figyelő. Minden, aminek túl kell élnie egy
ablakot, vagy amit két kliensnek azonosan kell látnia, ott él.
Egyetlen kliens sem nyitja meg maga az adatbázisfájlt. Helyette minden kliens
egyetlen RemoteRpcClient-et tart fenn, és azon keresztül indít
repóműveleteket és feliratkozásokat. A szerver a kapcsolatot egy párosított
eszközhöz tartozó, előre megosztott kulccsal hitelesíti — aztán többé nem
törődik a kapcsolattal. Egy munkamenet nincs munkaterülethez kötve. A
dispatcher állapotmentes: minden munkaterület-hatókörű hívás a saját
workspace_id-jét hordozza az argumentumaiban, és az olyan hívás, amelyből ez
hiányzik, elutasításra kerül.
Ez szándékos, és ez teszi lehetővé, hogy egy szerveren két kliens különböző munkaterületen üljön anélkül, hogy lenne egy szerveren tárolt „aktuális munkaterület”, amin összeveszhetnének. Az elszigetelést ehelyett hívásonként érvényesítjük, négy lépésben:
- A művelet deklarálja, hogy munkaterület-hatókörű-e; ha igen, és nem érkezett
workspace_id, a hívás elutasításra kerül. - A megnevezett azonosítónak regisztrált munkaterületnek kell lennie, ezt
még az előtt ellenőrizzük, hogy bármi adatbázist nyitna — különben egy
ismeretlen azonosító minden kérésnél megtestesítene egy üres, kísértetjárta
workspace.db-t. Egy hiányzó találat nem található hibát ad. - A hívó
WorkspaceRoleszerepének el kell érnie a művelet küszöbét, amely a művelet fajtájából adódik: az olvasáshoz vendég, a módosításhoz tag, a romboló művelethez admin szükséges. - Az olyan művelet, amely repótartalmat tesz elérhetővé, emellett az általa
deklarált szinten repónkénti engedélyt is megkövetel —
none/read/review/write—, így a munkaterületi tagság soha nem előzi meg csendben a kódhoszt jogosultságait.
A lényeges mondat: a párosítási kulcs birtoklása nem a hozzáférési határ; a tagság az.
Miért választottuk szét így
Szekció neve “Miért választottuk szét így”Három nyomás tolta a megoldást a szerver felé:
- Egyetlen igazságforrás. Az asztali gép és a telefon, illetve a laptop és az asztali gép ugyanazt a flottaállapotot látja. Ha mindegyik a saját adatbázisát birtokolná, eltávolodnának egymástól. Egyetlen szerverrel minden kliens ugyanazt az élő adatot olvassa.
- A web nem tudja magát kiszolgálni. A böngésző nem indíthat alfolyamatot és nem nyithat meg helyi fájlt, ezért egy webes build soha nem birtokolhatja az adatbázist, és nem futtathat ügynököt. Olyan szerverrel kell beszélnie, amely ezt megteszi. Ahelyett, hogy készült volna egy második, csak webes adatút, az asztali alkalmazást is ugyanerre az útra állítottuk.
- Headless működés. Egy szerver, amelyet egy kicsi gépen futtathat — elérhető a vonaton ülő telefonról vagy bárhonnan egy böngészőből —, hasznosabb, mint egy grafikus felület, amelyet nyitva kell hagynia.
A kompromisszum az, hogy a szerver mostantól függőség: ha nem fut, semmi sem működik. Az asztali alkalmazás alapértelmezett válasza erre, hogy maga indít egyet.
A kliensek
Szekció neve “A kliensek”Öt kliens éri el a szervert, mindegyik más formával és bizalmi profillal.
Asztali alkalmazás
Szekció neve “Asztali alkalmazás”A Flutter asztali alkalmazás (macOS, Windows, Linux) a teljes kliens. Első indításkor megkérdezi, hogyan működjön, majd megjegyzi a választást:
- Helyi: egy
cc_serverindítása és felügyelete ezen a gépen — ez az alapértelmezett, önmagában megálló, egyfelhasználós beállítás. Az asztali alkalmazás elindítja a szervert, amely az alkalmazástámogatási könyvtár alatt birtokolja az adatbázist, és loopbacken keresztül beszél vele. - Távoli: csatlakozás egy máshol futó
cc_server-hez biztonságos WebSocketen keresztül. Az adatok azon a szerveren élnek; ez az asztali alkalmazás pusztán megjelenítő.
Mindkét esetben az így létrejövő RPC-kliens felülírja az alkalmazás adatszolgáltatóját, így a teljes felület — minden képernyő, minden funkció — a szerveren keresztül olvas és ír. Az asztali alkalmazás soha nem nyúl közvetlenül az adatbázisfájlhoz.
Webes kliens
Szekció neve “Webes kliens”A webes build ugyanaz a Flutter-alkalmazás böngészőben futóra fordítva, az
app.usectrl.dev címen üzemeltetve, így nincs mit
telepíteni. A böngésző nem indíthat alfolyamatot, ezért a webes kliens mindig
távoli: wss://-en tárcsáz egy cc_server-t, és a teljes asztali felületet
rendereli. Csatlakozás után ugyanazokat a képernyőket mutatja ugyanazon flotta
ellenében, mert ugyanaz a kód fut ugyanazon az RPC-n. A hiányosságok azok a
néhány hely, ahol olyan natív képesség kell, amivel a böngésző nem rendelkezik
— ezek közül a legfontosabb a lentebb tárgyalt megbeszélésrögzítési minőségi
réteg, és ide tartoznak az operációs rendszer értesítései is.
Ezért nem ugyanaz az állítás, hogy „nincs letöltés”, és hogy „nincs szerver”. A
webes kliens a telepítést szünteti meg; a szervert nem. Amit tárcsáz, lehet egy
ugyanazon a laptopon futó cc_server — ws://localhost:9030, amelyhez nem
kell tanúsítvány, mert a böngészők a loopbacket megbízhatónak tekintik —, vagy
egy másik gépen futó, amelynek wss://-en keresztül elérhetőnek kell lennie, a
böngésző által megbízhatónak tartott tanúsítvánnyal. A cc_server megtagadja,
hogy TLS nélkül nem loopback címre kössön, ezért egy távoli szerver vagy a saját
tanúsítványát jelenti, vagy egy TLS-t lezáró proxyt, vagy egy alagutat vagy
VPN-t, amely biztosít egyet.
Maga a csomag külön van üzemeltetve attól a szervertől, amellyel beszél. Egy
önálló cc_server kiszolgálja az RPC-végpontot, az MCP-felületet és annak
proxyit, de nem szolgál ki webes csomagot — a statikusfájl-útvonal létezik a
szerverben, de az önálló binárison nincs webes gyökér beállítva, így nincs mit
kiszolgálnia a / alatt. A közzétett cc-webapp konténerkép az, amely a
csomagot üzemelteti, és a scripts/build_web.sh az, ami felépíti. A szerver csak
az --allowed-origins listáján szereplő böngésző-origineket fogadja el, amely
alapértelmezésben https://app.usectrl.dev, így a csomag saját üzemeltetése
azt jelenti, hogy hozzá kell adni annak originjét.
A média (profilképek, hírfolyamképek, PR-képernyőképek) a szerver proxyvégpontján keresztül halad, ahelyett hogy közvetlenül a felsőbb hosztokat érné el, így a böngésző soha nem tölt le tetszőleges origint. A telepített kliens kérésenkénti Content-Security Policy-t üt rá egy nem érzékeny cookie-ból, így csak a csatlakozott szerver originje engedélyezett.
Telefonos társalkalmazás (cc_remote)
Szekció neve “Telefonos társalkalmazás (cc_remote)”A Remote alkalmazás külön, könnyebb kliens — egy Flutter webes PWA a remote.usectrl.dev címen. Szándékosan nem a teljes alkalmazás. Egy brókeren keresztüli, végponttól végpontig lezárt WebSocket-relén párosít, és az eszközfelületnek egy túlnyomórészt olvasásra szolgáló szeletét beszéli: jegyek, üzenetek és a hírfolyam olvasása; válasz küldése vagy jegy frissítése.
A telefon alacsonyabb jogosultságú szereplő, mint egy helyi ügynök. Az alapértelmezés szerint tiltó eszközszabályzat, a minden keretet lezáró előre megosztott kulcs, egy munkamenet-képesség, amely a kiemelt műveleteket (például a párosítást) kizárja a társügyfélből, a fenti hívásonkénti szerep- és repóengedély-ellenőrzések, valamint a sebességkorlátozás együtt megakadályozzák, hogy egy jóváhagyott (vagy kiszivárgott) párosítás teljes körű távoli vezérléssé váljon. A teljes biztonsági modellt lásd a Távoli vezérlés és mobil oldalon.
MCP-kliensek
Szekció neve “MCP-kliensek”A külső eszközök — szerkesztők, más ügynökök, CLI-k —, amelyek a Model Context Protocolt beszélik, a szerver MCP-felületéhez csatlakoznak, és a típusos eszközregisztert használják. Ez a programozott integráció útja; nem grafikus felület. Lásd az Az MCP-szerver használata és az MCP-eszközök oldalt.
Flotta-végrehajtók (cc_worker)
Szekció neve “Flotta-végrehajtók (cc_worker)”A cc_worker egy headless, tisztán Dart bináris, amely párosít egy
cc_server-rel, deklarálja a gazdagép képességeit, és lízingelt feladatokat húz
le végrehajtásra. Ugyanazon az RPC-n keresztül streameli vissza a
folyamateseményeket, és nem tart fenn tartós állapotot: nincs adatbázis,
nincs hitelesítés, nincsenek jóváhagyások, nincsenek költségkeretek — ezek soha
nem hagyják el a cc_server-t. A worker egy végtag, nem második agy. Egy
mérvadó szerver, N buta végtag; nincs konszenzus, nincs worker–worker közötti
forgalom.
A lízingelt végrehajtás még mindig csak lízing-infrastruktúra. Az agentRun az
egyetlen fajta, amely valódi parancsot futtat (CC_JOB_COMMAND, vagy egy
visszhangzott prompt, ha nem adtak meg egyet). A pipelineStep, a codeIndex,
a goldenRender, a benchmark és az evalBatch jelenleg a git --version /
rev-parse HEAD parancsokkal próbálkozik, hogy a streamelési útvonal
működjön, anélkül hogy úgy tennénk, mintha azok a feladatok lefutottak volna.
Amit hirdet: az operációs rendszer, a CPU-architektúra, a magok száma, a RAM,
hogy elérhető-e egy Flutter SDK, és hogy a gazdagép mely
homokozó-háttérrendszerekkel rendelkezik (Windowson egyikkel sem). Egy dedikált
worker emellett mindig hirdeti az alwaysOn és acceptsParallel
tulajdonságokat is, amelyekhez a pin → prefer → spill ütemező helyez. Nincs
GPU- vagy ML-próba.
Egy önálló asztali telepítés ebből semmit sem vesz észre, mert a szokásos
feladatkiosztás egyáltalán nem a flottán keresztül megy. Van ugyan egy
implicit, folyamaton belüli worker regisztrálva a szerver gazdagépéhez, de ez
egy regisztrációs illesztési pont, amelybe nincsenek futtatók bekötve — a helyi
workerre ténylegesen ráhelyezett feladat végrehajtás helyett meghiúsul. Ma csak
egy valódi cc_worker hajt végre lízingelt feladatokat.
Mi hol fut
Szekció neve “Mi hol fut”| Terület | Szerver (cc_server) |
Flotta-végrehajtó (cc_worker) |
Asztali kliens | Webes / telefonos kliens |
|---|---|---|---|---|
| Adatbázisok (Drift/SQLite) | ezeket birtokolja | — | — | — |
| Hitelesítés, jóváhagyások, költségkeretek, identitás | ezt birtokolja | — | — | — |
| Pipeline-ok, összehangolók, orchestrációs figyelő | futtatja | — | — | — |
| MCP-eszközfelület | kiszolgálja | — | — | — |
| Ügynökvégrehajtás | végrehajtja (vagy lízingbe adja) | lízingelt feladatokat hajt végre | — | — |
| Felület renderelése | — | — | teljes | teljes (web) / túlnyomórészt olvasás (telefon) |
| Megbeszélés rögzítése (mikrofon + megbeszélés hangja) | — | — | natív rögzítés | csak weben, képmegosztás hangján keresztül |
| Naptár OAuth (Google) | tokeneket tárol | — | — | — |
A két szint homokozása nem egyforma. A cc_server az általa maga végrehajtott
futásokat a gazdagép operációs rendszerének homokozójába csomagolja, ahol van
ilyen háttérrendszer — Seatbelt macOS-en, bubblewrap Linuxon és WSL2-n —, és
Windowson vagy bwrap és socat hiányában a többi korlátra esik vissza. A
cc_worker egyáltalán nem homokozó. Hirdet egy sandbox képességet, hogy a
szerver platform szerint helyezhesse el a feladatokat, de a workerben semmi nem
alkalmaz ilyet: egy lízingelt feladat közvetlenül indul, csak a lízing környezete
és a kapott worktree szab határt neki. A munka lízingbe adása ezért akkor is a
homokozón kívülre viszi a végrehajtást, ha a gazdagépen van homokozó. Hogy mi
szab határt egy futásnak az egyes esetekben, azt lásd a
Homokozó és biztonság
oldalon.
A megbeszélés rögzítése egy kliensen történik, mert mikrofonra és a megbeszélés hangjára van szükség — egy szekrényben álló szerver nem tudja rögzíteni az Ön hívását. A felvételt ezután a szerver pipeline-ja összegzi, a jegyzeteket pedig ott tárolja, ahol minden kliens el tudja olvasni.
A webes kliens is rögzít, amit a táblázat formája elfedhet: a böngészőben megfogja a mikrofont és egy képmegosztás hangpályát is, és 16 kHz-es PCM-et streamel a szervernek. Ez a hangpálya kötelező számára, ezért ott, ahol a böngésző nem ad ilyet, explicit módon meghiúsul. Ami valóban csak asztali gépen érhető el, az a rögzítés körüli minőségi réteg — a natív processzoron keresztüli, jelszintű visszhangszűrés, a bemeneti szintmérő és a néma mikrofon figyelmeztetése, az összefoglaló újrafuttatása, a feldolgozás megszakítása és a naptár rögzítés és hivatkozás művelete.
Párosítás és bizalom
Szekció neve “Párosítás és bizalom”Minden kliens egy előre megosztott kulccsal igazolja magát, amelyet egyszer kell kiadni:
- Az asztali alkalmazás helyi módban minden indításkor friss kulcsot generál, és környezeti változókon keresztül adja át az elindított szervernek, így az asztali gépen nem tárolódik titok.
- A távoli kliensek (távoli asztali, web, telefon) a szerver
pairparancsa által kibocsátott kulcsot használják, amelyet az operációs rendszer kulcstárában (a telefonon pedig helyben) tárolnak.
A visszavonás azonnali, nem halasztott. A szerver figyeli a párosított eszközök tábláját, és másodperceken belül eldobja minden olyan nyitott munkamenetet, amelynek eszköze kikerült az aktív halmazból — a közvetlen WebSocket-úton és a reléúton egyaránt. Nem kell megvárnia, hogy az eszköz újracsatlakozzon ahhoz, hogy elvágja.
A kulcs soha nem halad át olyan URL-en, amelyet egy statikus hoszt láthat.
Amikor hivatkozással érkezik — a telefonon vagy egy böngészőben —, az
URL-töredékben utazik, a # utáni részben, amelyet a böngésző soha nem
küld el az oldalt üzemeltető szervernek. Ez az az invariancia, amit érdemes
megjegyezni, és mindkettőre érvényes. A webes kliensnek két másik belépési
pontja van: a csatlakozási űrlap, ahol közvetlenül beilleszti a szervert és a
kulcsot, valamint egy meghívókód, amelyet egy kizárólag ahhoz a böngészőhöz
kibocsátott hitelesítő adatra vált be.
Kapcsolódó fogalmak
Szekció neve “Kapcsolódó fogalmak”- Munkaterületek és elszigetelés: miért hordozza minden RPC-hívás a saját munkaterület-azonosítóját, és hogyan teszi szerkezetivé az elszigetelést az adatbázis kettéválasztása
- Architektúra: hogyan épül a kódbázis a szerver és kliensei köré
- Távoli vezérlés és mobil: a telefonos párosítás és a biztonsági modell
Kapcsolódó útmutatók
Szekció neve “Kapcsolódó útmutatók”- Headless szerver futtatása: indítson el egy
cc_server-t, és párosítson egy klienst - Csatlakozás távoli szerverhez: irányítsa az asztali vagy webes klienst egy máshol futó szerverre
- Eszköz párosítása: adjon hozzá egy telefont, egy második böngészőt vagy egy másik asztali gépet
- Flotta-worker futtatása: adjon hozzá egy
cc_worker-t, amely lízingelt feladatokat húz le