Ανάπτυξη και πελάτες
Το Control Center δεν είναι ένα πρόγραμμα. Είναι μια αρχιτεκτονική λεπτού πελάτη: ένας headless διακομιστής που κατέχει τα δεδομένα σας και ένα σύνολο πελατών που αποδίδουν μια διεπαφή πάνω από μία σύνδεση RPC προς αυτόν. Η κατανόηση αυτού του διαχωρισμού εξηγεί γιατί κάποια πράγματα τρέχουν εκεί που τρέχουν και τι μπορεί και τι δεν μπορεί να προσεγγίσει ο κάθε πελάτης.
Ο διακομιστής κατέχει τα δεδομένα
Ενότητα με τίτλο «Ο διακομιστής κατέχει τα δεδομένα»Μια διεργασία που ονομάζεται cc_server κρατά τις βάσεις δεδομένων — μια
μικρή global.db για κατάσταση σε επίπεδο διακομιστή συν ένα αρχείο SQLite ανά
χώρο εργασίας, που ανοίγονται με
τεμπελιά — και εκτελεί τη μακρόβια εργασία: μηχανές pipeline, reconcilers, την
επιφάνεια εργαλείων MCP και τον ακροατή ενορχήστρωσης. Ό,τι πρέπει να επιβιώσει
πέρα από ένα παράθυρο, ή που δύο πελάτες πρέπει να το βλέπουν πανομοιότυπο, ζει
εκεί.
Κανένας πελάτης δεν ανοίγει ο ίδιος ένα αρχείο βάσης δεδομένων. Αντ’ αυτού, κάθε
πελάτης κρατά ένα RemoteRpcClient και εκδίδει λειτουργίες αποθετηρίου και
συνδρομές μέσω αυτού. Ο διακομιστής ταυτοποιεί τη σύνδεση με ένα προκοινόχρηστο
κλειδί συζευγμένης συσκευής — και μετά σταματά να ασχολείται με τη σύνδεση. Μια
συνεδρία δεν είναι δεσμευμένη σε έναν χώρο εργασίας. Ο dispatcher είναι χωρίς
κατάσταση: κάθε κλήση με εμβέλεια χώρου εργασίας μεταφέρει το δικό της
workspace_id στα ορίσματά της και μια κλήση που το παραλείπει απορρίπτεται.
Αυτό είναι σκόπιμο και είναι αυτό που επιτρέπει σε δύο πελάτες σε έναν διακομιστή να βρίσκονται σε διαφορετικούς χώρους εργασίας χωρίς έναν «τρέχοντα χώρο εργασίας» που κρατά ο διακομιστής και για τον οποίο θα διαφωνούσαν. Η απομόνωση επιβάλλεται αντ’ αυτού ανά κλήση, σε τέσσερα βήματα:
- Η πράξη δηλώνει αν έχει εμβέλεια χώρου εργασίας· αν έχει και δεν έφτασε
workspace_id, η κλήση απορρίπτεται. - Το αναφερόμενο id πρέπει να είναι ένας καταχωρισμένος χώρος εργασίας, κάτι
που ελέγχεται πριν ανοίξει οτιδήποτε βάση δεδομένων — διαφορετικά ένα άγνωστο
id θα υλοποιούσε ένα άδειο φάντασμα
workspace.dbσε κάθε αίτημα. Μια αστοχία σημαίνει «δεν βρέθηκε». - Το
WorkspaceRoleτου καλούντος πρέπει να καλύπτει το ελάχιστο επίπεδο της πράξης, που προκύπτει από το είδος της: η ανάγνωση απαιτεί guest, η μεταβολή απαιτεί member, η καταστροφική ενέργεια απαιτεί admin. - Μια πράξη που εκθέτει περιεχόμενο αποθετηρίου απαιτεί επιπλέον εκχώρηση ανά
αποθετήριο στο επίπεδο που δηλώνει —
none/read/review/write— ώστε η συμμετοχή στον χώρο εργασίας να μην υπερβαίνει ποτέ σιωπηρά τα προνόμια του forge.
Η πρόταση που έχει σημασία: η κατοχή κλειδιού σύζευξης δεν είναι το όριο πρόσβασης· η συμμετοχή είναι.
Γιατί έγινε έτσι ο διαχωρισμός
Ενότητα με τίτλο «Γιατί έγινε έτσι ο διαχωρισμός»Τρεις πιέσεις οδήγησαν προς έναν διακομιστή:
- Μία πηγή αλήθειας. Ένας υπολογιστής και ένα τηλέφωνο, ή ένας φορητός και ένας σταθερός, πρέπει να βλέπουν την ίδια κατάσταση του στόλου. Αν το καθένα είχε τη δική του βάση δεδομένων, θα αποκλίνανε. Ένας μόνο διακομιστής σημαίνει ότι κάθε πελάτης διαβάζει τα ίδια ζωντανά δεδομένα.
- Το web δεν μπορεί να αυτοεξυπηρετηθεί. Ένα πρόγραμμα περιήγησης δεν μπορεί να εκκινήσει υποδιεργασία ή να ανοίξει τοπικό αρχείο, οπότε μια έκδοση web δεν μπορεί ποτέ να κατέχει τη βάση δεδομένων ή να εκτελέσει πράκτορα. Πρέπει να μιλά σε έναν διακομιστή που το κάνει. Αντί να χτιστεί ένα δεύτερο, αποκλειστικά web μονοπάτι δεδομένων, ο υπολογιστής μεταφέρθηκε στο ίδιο μονοπάτι.
- Headless λειτουργία. Ένας διακομιστής που μπορείτε να τρέξετε σε ένα μικρό μηχάνημα — προσβάσιμος από ένα τηλέφωνο στο τρένο ή από ένα πρόγραμμα περιήγησης οπουδήποτε — είναι πιο χρήσιμος από ένα GUI που πρέπει να αφήσετε ανοιχτό.
Το τίμημα είναι ότι ο διακομιστής είναι πλέον εξάρτηση: αν δεν τρέχει, τίποτα δεν λειτουργεί. Η προεπιλεγμένη απάντηση του υπολογιστή σε αυτό είναι να εκκινήσει ο ίδιος έναν.
Οι πελάτες
Ενότητα με τίτλο «Οι πελάτες»Πέντε πελάτες προσεγγίζουν τον διακομιστή, ο καθένας με διαφορετική μορφή και προφίλ εμπιστοσύνης.
Εφαρμογή υπολογιστή
Ενότητα με τίτλο «Εφαρμογή υπολογιστή»Η εφαρμογή Flutter για υπολογιστή (macOS, Windows, Linux) είναι ο πλήρης πελάτης. Στην πρώτη εκκίνηση ρωτά πώς πρέπει να λειτουργήσει και μετά θυμάται την επιλογή:
- Τοπικά: εκκινεί και επιτηρεί έναν
cc_serverσε αυτό το μηχάνημα — η προεπιλεγμένη, αυτοτελής ρύθμιση για έναν χρήστη. Ο υπολογιστής εκκινεί τον διακομιστή, ο οποίος κατέχει τη βάση δεδομένων κάτω από τη ρίζα app-support και μιλά μαζί του μέσω loopback. - Απομακρυσμένα: συνδέεται σε έναν
cc_serverπου τρέχει αλλού μέσω ασφαλούς WebSocket. Τα δεδομένα ζουν σε εκείνον τον διακομιστή· αυτός ο υπολογιστής είναι απλώς αποδότης.
Και στις δύο περιπτώσεις, ο πελάτης RPC που προκύπτει αντικαθιστά τον πάροχο δεδομένων της εφαρμογής, οπότε ολόκληρη η διεπαφή — κάθε οθόνη, κάθε λειτουργία — διαβάζει και γράφει μέσω του διακομιστή. Ο υπολογιστής δεν αγγίζει ποτέ απευθείας το αρχείο της βάσης δεδομένων.
Πελάτης web
Ενότητα με τίτλο «Πελάτης web»Η έκδοση web είναι η ίδια εφαρμογή Flutter μεταγλωττισμένη ώστε να τρέχει σε
πρόγραμμα περιήγησης, φιλοξενείται στο app.usectrl.dev
ώστε να μην υπάρχει τίποτα να εγκαταστήσετε. Ένα πρόγραμμα περιήγησης δεν μπορεί
να εκκινήσει υποδιεργασία, οπότε ο πελάτης web είναι πάντα απομακρυσμένος:
καλεί έναν cc_server μέσω wss:// και αποδίδει την πλήρη διεπαφή του
υπολογιστή. Μόλις συνδεθεί, δείχνει τις ίδιες οθόνες απέναντι στον ίδιο στόλο,
επειδή είναι ο ίδιος κώδικας πάνω από το ίδιο RPC. Τα κενά είναι οι λίγες θέσεις
που χρειάζονται μια εγγενή δυνατότητα που δεν έχει το πρόγραμμα περιήγησης — το
επίπεδο ποιότητας της καταγραφής σύσκεψης πιο κάτω είναι το κύριο και οι
ειδοποιήσεις του λειτουργικού συστήματος είναι ένα άλλο.
Γι’ αυτό το «χωρίς λήψη» και το «χωρίς διακομιστή» είναι διαφορετικοί ισχυρισμοί.
Ο πελάτης web αφαιρεί την εγκατάσταση· δεν αφαιρεί τον διακομιστή. Αυτό που
καλεί μπορεί να είναι ένας cc_server στον ίδιο φορητό υπολογιστή —
ws://localhost:9030, που δεν χρειάζεται πιστοποιητικό επειδή τα προγράμματα
περιήγησης θεωρούν το loopback αξιόπιστο — ή ένας σε άλλο μηχάνημα, ο οποίος
πρέπει να είναι προσβάσιμος μέσω wss:// με πιστοποιητικό που εμπιστεύεται το
πρόγραμμα περιήγησης. Ο cc_server αρνείται να δεσμεύσει διεύθυνση εκτός
loopback χωρίς TLS, οπότε ένας απομακρυσμένος διακομιστής σημαίνει είτε δικό του
πιστοποιητικό, είτε proxy τερματισμού TLS, είτε σήραγγα ή VPN που παρέχει ένα.
Το ίδιο το bundle φιλοξενείται χωριστά από τον διακομιστή με τον οποίο μιλά. Ένας
αυτόνομος cc_server εξυπηρετεί το τελικό σημείο RPC, την επιφάνεια MCP και τα
proxy της, αλλά όχι ένα bundle web — η διαδρομή στατικών αρχείων υπάρχει στον
διακομιστή αλλά καμία ρίζα web δεν έχει ρυθμιστεί στο αυτόνομο εκτελέσιμο, οπότε
δεν έχει τίποτα να εξυπηρετήσει στο /. Το δημοσιευμένο image container
cc-webapp είναι αυτό που φιλοξενεί το bundle και το scripts/build_web.sh είναι
αυτό που το χτίζει. Ένας διακομιστής δέχεται προελεύσεις προγράμματος περιήγησης
μόνο από τη λίστα --allowed-origins, που έχει ως προεπιλογή το
https://app.usectrl.dev, οπότε η αυτοφιλοξενία του bundle σημαίνει προσθήκη της
προέλευσής του.
Τα πολυμέσα (άβαταρ, εικόνες ροής, στιγμιότυπα PR) δρομολογούνται μέσω του τελικού σημείου proxy του διακομιστή αντί να χτυπούν απευθείας ανάντη hosts, ώστε ένα πρόγραμμα περιήγησης να μην ανακτά ποτέ αυθαίρετη προέλευση. Ο αναπτυγμένος πελάτης αποτυπώνει μια πολιτική Content-Security ανά αίτημα από ένα μη ευαίσθητο cookie, ώστε να επιτρέπεται μόνο η προέλευση του συνδεδεμένου διακομιστή.
Σύντροφος τηλεφώνου (cc_remote)
Ενότητα με τίτλο «Σύντροφος τηλεφώνου (cc_remote)»Η εφαρμογή Remote είναι ένας ξεχωριστός, ελαφρύτερος πελάτης — μια PWA Flutter web στο remote.usectrl.dev. Δεν είναι σκόπιμα η πλήρης εφαρμογή. Συζεύγνυται μέσω ενός διαμεσολαβημένου αναμεταδότη WebSocket, σφραγισμένου από άκρο σε άκρο, και μιλά ένα κυρίως αναγνωστικό τμήμα της επιφάνειας εργαλείων: ανάγνωση εισιτηρίων, μηνυμάτων και ροής ειδήσεων· αποστολή απάντησης ή ενημέρωση εισιτηρίου.
Ένα τηλέφωνο είναι ένα υποκείμενο με χαμηλότερα προνόμια από έναν τοπικό πράκτορα. Μια πολιτική εργαλείων «άρνηση εξ ορισμού», ένα προκοινόχρηστο κλειδί που σφραγίζει κάθε πλαίσιο, μια δυνατότητα συνεδρίας που αποκλείει προνομιούχες πράξεις (τη σύζευξη, για παράδειγμα) από έναν πελάτη-σύντροφο, οι έλεγχοι ρόλου και εκχώρησης αποθετηρίου ανά κλήση παραπάνω και ο περιορισμός ρυθμού εμποδίζουν μια εγκεκριμένη (ή διερρηγμένη) σύζευξη να γίνει πλήρης απομακρυσμένος έλεγχος. Δείτε τον Απομακρυσμένο έλεγχο και το κινητό για το πλήρες μοντέλο ασφαλείας.
Πελάτες MCP
Ενότητα με τίτλο «Πελάτες MCP»Εξωτερικά εργαλεία — editors, άλλοι πράκτορες, CLI — που μιλούν το Model Context Protocol συνδέονται στην επιφάνεια MCP του διακομιστή και καταναλώνουν το τυποποιημένο μητρώο εργαλείων. Αυτό είναι το μονοπάτι προγραμματιστικής ενσωμάτωσης· δεν είναι GUI. Δείτε τη Χρήση του διακομιστή MCP και την Αναφορά εργαλείων MCP.
Εκτελεστές στόλου (cc_worker)
Ενότητα με τίτλο «Εκτελεστές στόλου (cc_worker)»Ένας cc_worker είναι ένα headless εκτελέσιμο σε καθαρή Dart που συζεύγνυται
με έναν cc_server, δηλώνει τις δυνατότητες του ξενιστή του και τραβά μισθωμένες
εργασίες για εκτέλεση. Ρέει γεγονότα διεργασίας πίσω μέσω του ίδιου RPC και δεν
κρατά καμία μόνιμη κατάσταση: χωρίς βάση δεδομένων, χωρίς ταυτοποίηση, χωρίς
εγκρίσεις, χωρίς προϋπολογισμούς — αυτά δεν φεύγουν ποτέ από τον cc_server. Ένας
εργάτης είναι ένα άκρο, όχι δεύτερος εγκέφαλος. Ένας διακομιστής με την αυθεντία,
N χαζά άκρα· δεν υπάρχει συναίνεση, δεν υπάρχει κίνηση μεταξύ εργατών.
Η μισθωμένη εκτέλεση είναι ακόμη υδραυλικά μίσθωσης. Το agentRun είναι ο μόνος
τύπος που εκτελεί πραγματική εντολή (CC_JOB_COMMAND, ή μια προτροπή που
επαναλαμβάνεται αν δεν δόθηκε καμία). Τα pipelineStep, codeIndex,
goldenRender, benchmark και evalBatch αυτή τη στιγμή δοκιμάζουν με
git --version / rev-parse HEAD, ώστε να ασκείται το μονοπάτι ροής χωρίς να
παριστάνεται ότι εκτελέστηκαν αυτές οι εργασίες.
Αυτό που διαφημίζει είναι το λειτουργικό σύστημα, την αρχιτεκτονική CPU, τον αριθμό
πυρήνων, τη RAM, αν είναι προσβάσιμο ένα Flutter SDK και ποια υποσυστήματα sandbox
έχει ο ξενιστής (κανένα στα Windows). Ένας αποκλειστικός εργάτης διαφημίζει
επίσης πάντα τα alwaysOn και acceptsParallel, στα οποία βασίζει την τοποθέτηση
ο χρονοπρογραμματιστής pin → prefer → spill. Δεν υπάρχει ανίχνευση GPU ή ML.
Ένας μεμονωμένος υπολογιστής δεν παρατηρεί τίποτα από αυτά, επειδή η συνήθης
αποστολή δεν περνά καθόλου από τον στόλο. Υπάρχει πράγματι ένας σιωπηρός
εργάτης εντός διεργασίας, καταχωρισμένος για τον ξενιστή του διακομιστή, αλλά
είναι μια ραφή καταχώρισης χωρίς εκτελεστές συνδεδεμένους σε αυτή — μια εργασία
που όντως τοποθετείται στον τοπικό εργάτη αποτυγχάνει αντί να εκτελεστεί. Σήμερα,
μόνο ένας πραγματικός cc_worker εκτελεί μισθωμένες εργασίες.
Τι τρέχει πού
Ενότητα με τίτλο «Τι τρέχει πού»| Θέμα | Διακομιστής (cc_server) |
Εκτελεστής στόλου (cc_worker) |
Πελάτης υπολογιστή | Πελάτης web / τηλεφώνου |
|---|---|---|---|---|
| Βάσεις δεδομένων (Drift/SQLite) | τις κατέχει | — | — | — |
| Ταυτοποίηση, εγκρίσεις, προϋπολογισμοί, ταυτότητα | τα κατέχει | — | — | — |
| Pipeline, reconcilers, ακροατής ενορχήστρωσης | τα εκτελεί | — | — | — |
| Επιφάνεια εργαλείων MCP | την εξυπηρετεί | — | — | — |
| Εκτέλεση πρακτόρων | την εκτελεί (ή τη μισθώνει προς τα έξω) | εκτελεί μισθωμένες εργασίες | — | — |
| Απόδοση διεπαφής | — | — | πλήρης | πλήρης (web) / κυρίως ανάγνωση (τηλέφωνο) |
| Καταγραφή σύσκεψης (μικρόφωνο + ήχος σύσκεψης) | — | — | εγγενής καταγραφή | μόνο web, μέσω ήχου κοινής χρήσης οθόνης |
| OAuth ημερολογίου (Google) | αποθηκεύει tokens | — | — | — |
Τα δύο επίπεδα δεν εφαρμόζουν sandbox με τον ίδιο τρόπο. Ο cc_server τυλίγει τις
εκτελέσεις που εκτελεί ο ίδιος στο sandbox του λειτουργικού συστήματος του ξενιστή
όπου υπάρχει υποσύστημα — Seatbelt στο macOS, bubblewrap στο Linux και το WSL2 —
και καταφεύγει στα άλλα όρια στα Windows ή χωρίς τα bwrap και socat. Ο
cc_worker δεν εφαρμόζει καθόλου sandbox. Διαφημίζει μια δυνατότητα sandbox,
ώστε ο διακομιστής να τοποθετεί εργασίες ανά πλατφόρμα, αλλά τίποτα στον εργάτη
δεν εφαρμόζει κάποιο: μια μισθωμένη εργασία εκκινείται απευθείας, περιορισμένη από
το περιβάλλον της μίσθωσης και το worktree που της δόθηκε. Η μίσθωση εργασίας προς
τα έξω μετακινεί επομένως την εκτέλεση έξω από το sandbox, ακόμη και σε ξενιστή
που διαθέτει ένα. Δείτε το
Sandbox και ασφάλεια για το τι
περιορίζει μια εκτέλεση σε κάθε περίπτωση.
Η καταγραφή σύσκεψης γίνεται σε έναν πελάτη, επειδή χρειάζεται μικρόφωνο και τον ήχο της σύσκεψης — ένας διακομιστής σε μια ντουλάπα δεν μπορεί να ηχογραφήσει την κλήση σας. Η ηχογράφηση συνοψίζεται μετά από το pipeline του διακομιστή και οι σημειώσεις αποθηκεύονται εκεί όπου κάθε πελάτης μπορεί να τις διαβάσει.
Ο πελάτης web καταγράφει επίσης, κάτι που η μορφή του πίνακα μπορεί να επισκιάσει: συλλαμβάνει το μικρόφωνο συν ένα κομμάτι ήχου κοινής χρήσης οθόνης στο πρόγραμμα περιήγησης και ρέει PCM 16 kHz προς τον διακομιστή. Απαιτεί υποχρεωτικά αυτό το κομμάτι ήχου, οπότε αποτυγχάνει ρητά όπου το πρόγραμμα περιήγησης δεν παρέχει ένα. Αυτό που είναι πραγματικά μόνο για υπολογιστή είναι το επίπεδο ποιότητας γύρω από την καταγραφή — ακύρωση ηχούς σε επίπεδο σήματος μέσω του εγγενούς επεξεργαστή, ο μετρητής στάθμης εισόδου και η προειδοποίηση σίγασης μικροφώνου, η επανεκτέλεση σύνοψης, η ακύρωση επεξεργασίας και η δράση «Εγγραφή και σύνδεση» του ημερολογίου.
Σύζευξη και εμπιστοσύνη
Ενότητα με τίτλο «Σύζευξη και εμπιστοσύνη»Κάθε πελάτης αποδεικνύει την ταυτότητά του με ένα προκοινόχρηστο κλειδί που παρέχεται μία φορά:
- Ο υπολογιστής σε τοπική λειτουργία δημιουργεί ένα νέο κλειδί σε κάθε εκκίνηση και το παραδίδει στον εκκινημένο διακομιστή μέσω περιβάλλοντος, ώστε τίποτα μυστικό να μην αποθηκεύεται μόνιμα στον υπολογιστή.
- Οι απομακρυσμένοι πελάτες (υπολογιστής σε απομακρυσμένη λειτουργία, web,
τηλέφωνο) χρησιμοποιούν ένα κλειδί που παράγεται από την εντολή
pairτου διακομιστή και αποθηκεύεται στην κλειδοθήκη του λειτουργικού συστήματος (ή, στο τηλέφωνο, τοπικά).
Η ανάκληση είναι ζωντανή, όχι οκνηρή. Ο διακομιστής παρακολουθεί τον πίνακα συζευγμένων συσκευών του και απορρίπτει κάθε ανοιχτή συνεδρία της οποίας η συσκευή έχει φύγει από το ενεργό σύνολο, μέσα σε δευτερόλεπτα — στο άμεσο μονοπάτι WebSocket και στο μονοπάτι του αναμεταδότη το ίδιο. Δεν χρειάζεται να περιμένετε να επανασυνδεθεί η συσκευή για να την αποκόψετε.
Το κλειδί δεν ταξιδεύει ποτέ μέσα από ένα URL που μπορεί να δει ένας στατικός
ξενιστής. Όταν φτάνει μέσω συνδέσμου — στο τηλέφωνο ή σε ένα πρόγραμμα περιήγησης
— ταξιδεύει στο τμήμα URL (fragment), το μέρος μετά το #, που το πρόγραμμα
περιήγησης δεν στέλνει ποτέ στον διακομιστή που φιλοξενεί τη σελίδα. Αυτή είναι η
αναλλοίωτη συνθήκη που αξίζει να θυμάστε και ισχύει και για τα δύο. Ο πελάτης web
έχει δύο άλλα σημεία εισόδου: τη φόρμα σύνδεσης, όπου επικολλάτε απευθείας έναν
διακομιστή και ένα κλειδί, και έναν κωδικό πρόσκλησης, τον οποίο εξαργυρώνει για
ένα διαπιστευτήριο που παράγεται αποκλειστικά για αυτό το πρόγραμμα περιήγησης.
Σχετικές έννοιες
Ενότητα με τίτλο «Σχετικές έννοιες»- Χώροι εργασίας και απομόνωση: γιατί κάθε κλήση RPC μεταφέρει το δικό της workspace id και πώς ο διαχωρισμός της βάσης δεδομένων κάνει την απομόνωση δομική
- Αρχιτεκτονική: πώς ο κώδικας είναι δομημένος γύρω από τον διακομιστή και τους πελάτες του
- Απομακρυσμένος έλεγχος και κινητό: το μοντέλο σύζευξης τηλεφώνου και ασφάλειας
Σχετικοί οδηγοί
Ενότητα με τίτλο «Σχετικοί οδηγοί»- Εκτέλεση headless διακομιστή: ξεκινήστε έναν
cc_serverκαι συζεύξτε έναν πελάτη - Σύνδεση σε απομακρυσμένο διακομιστή: κατευθύνετε τον πελάτη υπολογιστή ή web σε έναν διακομιστή αλλού
- Σύζευξη συσκευής: προσθέστε ένα τηλέφωνο, ένα δεύτερο πρόγραμμα περιήγησης ή έναν άλλο υπολογιστή
- Εκτέλεση εργάτη στόλου: προσθέστε έναν
cc_workerπου τραβά μισθωμένες εργασίες