Langkau ke kandungan

Penerapan dan klien

Control Center bukan satu program tunggal. Ia ialah seni bina klien nipis: sebuah pelayan tanpa kepala yang memiliki data anda dan sekumpulan klien yang memaparkan antara muka melalui satu sambungan RPC kepadanya. Memahami pemisahan ini menjelaskan mengapa sesetengah perkara berjalan di tempatnya dan apa yang boleh dan tidak boleh dicapai oleh setiap klien.

Satu proses yang dipanggil cc_server memegang pangkalan data — global.db yang kecil untuk keadaan seluruh pelayan serta satu fail SQLite bagi setiap ruang kerja, dibuka secara malas — dan menjalankan kerja jangka panjang: enjin pipeline, reconciler, permukaan alat MCP dan pendengar orkestrasi. Segala yang perlu hidup lebih lama daripada tetingkap, atau yang patut dilihat secara serupa oleh dua klien, tinggal di situ.

Tiada klien membuka sendiri fail pangkalan data. Sebaliknya, setiap klien memegang satu RemoteRpcClient dan mengeluarkan operasi repo serta langganan melaluinya. Pelayan mengesahkan sambungan itu terhadap kunci pra-kongsi peranti berpasangan — dan selepas itu tidak lagi mengambil berat tentang sambungan tersebut. Sesi tidak terikat pada ruang kerja. Penghantar itu tanpa keadaan: setiap panggilan berlingkup ruang kerja membawa workspace_id sendiri dalam argumennya, dan panggilan yang terlepas satu akan ditolak.

Itu memang disengajakan, dan itulah yang membolehkan dua klien pada satu pelayan berada dalam ruang kerja yang berbeza tanpa “ruang kerja semasa” yang dipegang pelayan untuk mereka perselisihkan. Sebaliknya, pengasingan dikuatkuasakan bagi setiap panggilan, dalam empat langkah:

  1. Operasi mengisytiharkan sama ada ia berlingkup ruang kerja; jika ya dan tiada workspace_id diterima, panggilan itu ditolak.
  2. Id yang dinamakan mesti ruang kerja yang berdaftar, diperiksa sebelum apa-apa membuka pangkalan data — jika tidak, id yang tidak dikenali akan mewujudkan workspace.db hantu yang kosong pada setiap permintaan. Kegagalan padan bermakna tidak dijumpai.
  3. WorkspaceRole pemanggil mesti memenuhi paras minimum operasi, yang diterbitkan daripada jenisnya: baca memerlukan guest, mutasi memerlukan member, pemusnahan memerlukan admin.
  4. Operasi yang mendedahkan kandungan repo turut memerlukan kebenaran per repo pada tahap yang diisytiharkannya — none / read / review / write — supaya keahlian ruang kerja tidak pernah secara senyap memberi keistimewaan melebihi hos kod.

Ayat yang penting: memegang kunci pasangan bukanlah sempadan akses; keahlianlah sempadan itu.

Tiga tekanan mendorong ke arah pelayan:

  1. Satu sumber kebenaran. Desktop dan telefon, atau komputer riba dan desktop, sepatutnya melihat keadaan armada yang sama. Jika setiap satu memiliki pangkalan datanya sendiri, kedua-duanya akan terpesong. Satu pelayan tunggal bermakna setiap klien membaca data langsung yang sama.
  2. Web tidak boleh melayan dirinya sendiri. Penyemak imbas tidak boleh melahirkan subproses atau membuka fail setempat, jadi binaan web tidak akan sekali-kali dapat memiliki pangkalan data atau menjalankan ejen. Ia mesti bercakap dengan pelayan yang boleh berbuat demikian. Daripada membina laluan data kedua yang khusus untuk web, desktop dibawa ke laluan yang sama.
  3. Operasi tanpa kepala. Pelayan yang boleh anda jalankan pada kotak kecil — dapat dicapai daripada telefon dalam kereta api atau penyemak imbas di mana-mana — lebih berguna daripada GUI yang mesti anda biarkan terbuka.

Kos timbal baliknya ialah pelayan kini menjadi kebergantungan: jika ia tidak berjalan, tiada apa yang berfungsi. Jawapan lalai desktop untuk itu ialah melahirkan satu sendiri.

Lima klien mencapai pelayan, masing-masing dengan bentuk dan profil kepercayaan yang berbeza.

Aplikasi desktop Flutter (macOS, Windows, Linux) ialah klien penuh. Pada pelancaran pertama ia bertanya bagaimana ia patut berjalan, kemudian mengingati pilihan itu:

  • Setempat: lahirkan dan awasi cc_server pada mesin ini — penyiapan lalai, serba lengkap dan pengguna tunggal. Desktop melancarkan pelayan itu, yang memiliki pangkalan data di bawah akar sokongan apl dan bercakap dengannya melalui loopback.
  • Jauh: sambung ke cc_server yang berjalan di tempat lain melalui WebSocket yang selamat. Data tinggal pada pelayan itu; desktop ini semata-mata pemapar.

Dalam kedua-dua kes, klien RPC yang terhasil menggantikan pembekal data apl, jadi keseluruhan UI — setiap skrin, setiap ciri — membaca dan menulis melalui pelayan. Desktop tidak pernah menyentuh fail pangkalan data secara langsung.

Binaan web ialah apl Flutter yang sama, dikompil untuk berjalan dalam penyemak imbas dan dihoskan di app.usectrl.dev, jadi tiada apa yang perlu dipasang. Penyemak imbas tidak boleh melahirkan subproses, jadi klien web sentiasa jauh: ia mendail cc_server melalui wss:// dan memaparkan antara muka desktop yang penuh. Sebaik sahaja bersambung, ia menunjukkan skrin yang sama terhadap armada yang sama, kerana ia kod yang sama melalui RPC yang sama. Jurangnya ialah segelintir tempat yang memerlukan keupayaan natif yang tiada pada penyemak imbas — lapisan kualiti rakaman mesyuarat di bawah ialah yang utama, dan pemberitahuan OS ialah satu lagi.

Inilah sebabnya “tiada muat turun” dan “tiada pelayan” ialah dua dakwaan yang berbeza. Klien web menghapuskan pemasangan; ia tidak menghapuskan pelayan. Apa yang didailnya boleh jadi cc_server pada komputer riba yang sama — ws://localhost:9030, yang tidak memerlukan sijil kerana penyemak imbas menganggap loopback sebagai boleh dipercayai — atau satu pada mesin lain, yang mesti dapat dicapai melalui wss:// dengan sijil yang dipercayai oleh penyemak imbas. cc_server enggan mengikat alamat bukan loopback tanpa TLS, jadi pelayan jauh bermakna sama ada sijilnya sendiri, proksi penamat TLS, atau terowong atau VPN yang membekalkannya.

Bundel itu sendiri dihoskan secara berasingan daripada pelayan yang dihubunginya. cc_server berdiri sendiri menyajikan titik akhir RPC, permukaan MCP dan proksinya, tetapi bukan bundel web — laluan fail statik wujud dalam pelayan itu, tetapi tiada akar web dikonfigurasikan pada binari berdiri sendiri, jadi ia tiada apa-apa untuk disajikan pada /. Imej kontena cc-webapp yang diterbitkan ialah yang menghoskan bundel itu, dan scripts/build_web.sh ialah yang membinanya. Pelayan hanya menerima asalan penyemak imbas yang tersenarai dalam --allowed-origins, yang lalai kepada https://app.usectrl.dev, jadi menghoskan bundel itu sendiri bermakna menambah asalannya.

Media (avatar, imej suapan, tangkapan skrin PR) melalui titik akhir proksi pelayan dan bukan menghubungi hos huluan secara langsung, jadi penyemak imbas tidak pernah mengambil asalan sewenang-wenangnya. Klien yang diterapkan mengecop Content-Security Policy bagi setiap permintaan daripada kuki tidak sensitif, supaya hanya asalan pelayan yang bersambung dibenarkan.

Aplikasi Remote ialah klien berasingan yang lebih ringan — PWA web Flutter di remote.usectrl.dev. Ia sengaja bukan apl penuh. Ia mengganding melalui geganti WebSocket yang diuruskan oleh broker dan dimeterai hujung ke hujung, serta menuturkan hirisan permukaan alat yang sebahagian besarnya baca: baca tiket, mesej dan suapan berita; hantar balasan atau kemas kini tiket.

Telefon ialah prinsipal berkeistimewaan lebih rendah daripada ejen setempat. Dasar alat yang menolak secara lalai, kunci pra-kongsi yang memeterai setiap rangka, keupayaan sesi yang mengunci operasi berkeistimewaan (penggandingan, misalnya) keluar daripada klien pendamping, pemeriksaan peranan dan kebenaran repo bagi setiap panggilan di atas, serta pengehadan kadar menghalang penggandingan yang diluluskan (atau bocor) daripada menjadi kawalan jauh penuh. Lihat Kawalan jauh dan mudah alih untuk model keselamatan yang penuh.

Alat luaran — editor, ejen lain, CLI — yang menuturkan Model Context Protocol menyambung ke permukaan MCP pelayan dan menggunakan daftar alat bertaip. Ini ialah laluan integrasi berprogram; ia bukan GUI. Lihat Gunakan pelayan MCP dan Rujukan alat MCP.

cc_worker ialah binari Dart tulen tanpa kepala yang mengganding dengan cc_server, mengisytiharkan keupayaan hosnya dan menarik tugas pajakan untuk dilaksanakan. Ia menstrim acara proses kembali melalui RPC yang sama dan tidak memegang sebarang keadaan berkekalan: tiada pangkalan data, tiada pengesahan, tiada kelulusan, tiada bajet — semuanya tidak pernah meninggalkan cc_server. Pekerja ialah anggota badan, bukan otak kedua. Satu pelayan berwibawa, N anggota badan yang bodoh; tiada konsensus, tiada trafik pekerja ke pekerja.

Pelaksanaan berpajak masih hanyalah saluran paip pajakan. agentRun ialah satu-satunya jenis yang menjalankan arahan sebenar (CC_JOB_COMMAND, atau gesaan yang digaungkan jika tiada yang dibekalkan). pipelineStep, codeIndex, goldenRender, benchmark dan evalBatch kini menyiasat dengan git --version / rev-parse HEAD supaya laluan penstriman dapat diuji tanpa berpura-pura tugas itu benar-benar berjalan.

Yang dihebahkannya ialah sistem pengendalian, seni bina CPU, bilangan teras, RAM, sama ada SDK Flutter dapat dicapai dan bahagian belakang kotak pasir yang ada pada hos (tiada pada Windows). Pekerja khusus juga sentiasa menghebahkan alwaysOn dan acceptsParallel, dan itulah asas penempatan oleh penjadual pin → prefer → spill. Tiada penyiasatan GPU atau ML.

Desktop tunggal tidak menyedari semua ini, kerana penghantaran biasa tidak melalui armada sama sekali. Wujud pekerja tersirat dalam proses yang didaftarkan untuk hos pelayan, tetapi ia hanyalah titik sambungan pendaftaran tanpa pelaksana yang dipasang padanya — tugas yang benar-benar diletakkan pada pekerja setempat akan gagal dan bukannya dilaksanakan. Hari ini, hanya cc_worker sebenar yang melaksanakan tugas pajakan.

Perkara Pelayan (cc_server) Pelaksana armada (cc_worker) Klien desktop Klien web / telefon
Pangkalan data (Drift/SQLite) memilikinya — — —
Pengesahan, kelulusan, bajet, identiti memilikinya — — —
Pipeline, reconciler, pendengar orkestrasi menjalankannya — — —
Permukaan alat MCP menyajikannya — — —
Pelaksanaan ejen menjalankannya (atau memajakkannya keluar) melaksanakan tugas pajakan — —
Pemaparan UI — — penuh penuh (web) / banyak membaca (telefon)
Rakaman mesyuarat (mik + audio mesyuarat) — — rakaman natif web sahaja, melalui audio kongsi skrin
OAuth kalendar (Google) menyimpan token — — —

Kedua-dua lapisan tidak mengasingkan dengan cara yang sama. cc_server membalut larian yang dilaksanakannya sendiri dalam kotak pasir OS hos di mana ada bahagian belakangnya — Seatbelt pada macOS, bubblewrap pada Linux dan WSL2 — dan kembali kepada sempadan lain pada Windows atau tanpa bwrap dan socat. cc_worker tidak mengasingkan sama sekali. Ia menghebahkan keupayaan sandbox supaya pelayan boleh menempatkan tugas mengikut platform, tetapi tiada apa-apa dalam pekerja itu yang menerapkannya: tugas pajakan dilahirkan secara langsung, terbatas pada persekitaran pajakan dan worktree yang diberikan kepadanya. Oleh itu, memajakkan kerja keluar memindahkan pelaksanaan ke luar kotak pasir walaupun pada hos yang memilikinya. Lihat Kotak pasir dan keselamatan untuk apa yang mengehadkan sesuatu larian dalam setiap kes.

Rakaman mesyuarat berlaku pada klien kerana ia memerlukan mikrofon dan audio mesyuarat itu — pelayan di dalam almari tidak boleh merakam panggilan anda. Rakaman itu kemudiannya diringkaskan oleh pipeline pelayan, dan nota disimpan di tempat yang boleh dibaca oleh setiap klien.

Klien web juga merakam, sesuatu yang bentuk jadual itu boleh mengaburkan: ia menangkap mikrofon serta trek audio kongsi skrin dalam penyemak imbas dan menstrim PCM 16 kHz ke pelayan. Ia memerlukan trek audio itu, jadi ia gagal secara nyata di tempat penyemak imbas tidak membekalkannya. Yang benar-benar khusus desktop ialah lapisan kualiti di sekeliling rakaman — pembatalan gema pada peringkat isyarat melalui pemproses natif, meter aras input dan amaran mikrofon mati, menjalankan semula ringkasan, membatalkan pemprosesan dan tindakan rakam-dan-paut kalendar.

Setiap klien membuktikan identitinya dengan kunci pra-kongsi yang diperuntukkan sekali:

  • Desktop dalam modus setempat menjana kunci baharu pada setiap but dan menyerahkannya kepada pelayan yang dilahirkan melalui persekitaran, jadi tiada apa-apa yang rahsia disimpan secara kekal pada desktop.
  • Klien jauh (desktop jauh, web, telefon) menggunakan kunci yang ditempa oleh perintah pair pelayan dan disimpan dalam rantai kunci OS (atau, pada telefon, secara setempat).

Penarikan balik adalah langsung, bukan malas. Pelayan memantau jadual peranti berpasangannya dan menggugurkan mana-mana sesi terbuka yang perantinya telah keluar daripada set aktif, dalam beberapa saat — pada laluan WebSocket langsung dan laluan geganti sama-sama. Anda tidak perlu menunggu peranti itu menyambung semula untuk memutuskan aksesnya.

Kunci itu tidak pernah melalui URL yang boleh dilihat oleh hos statik. Apabila ia tiba melalui pautan — pada telefon atau dalam penyemak imbas — ia menunggang dalam serpihan URL, bahagian selepas #, yang tidak pernah dihantar oleh penyemak imbas kepada pelayan yang menghoskan halaman itu. Itulah invarian yang wajar diingati, dan ia terpakai pada kedua-duanya. Klien web mempunyai dua lagi titik masuk: borang sambungan, tempat anda menampal pelayan dan kunci secara langsung, dan kod jemputan, yang ditebusnya untuk kelayakan yang ditempa khusus untuk penyemak imbas itu sahaja.

  • Ruang kerja dan pengasingan: mengapa setiap panggilan RPC membawa id ruang kerjanya sendiri dan bagaimana pemisahan pangkalan data menjadikan pengasingan bersifat struktur
  • Seni bina: bagaimana pangkalan kod distrukturkan di sekeliling pelayan dan kliennya
  • Kawalan jauh dan mudah alih: model penggandingan telefon dan keselamatan