Εκτέλεση headless διακομιστή
Εκτελέστε το cc_server σε ένα μηχάνημα που μένει ανοιχτό και μετά συνδεθείτε σε
αυτόν από την εφαρμογή υπολογιστή, ένα πρόγραμμα περιήγησης ή το τηλέφωνό σας. Ο
διακομιστής είναι ένα εγγενές δυαδικό αποκλειστικά Dart — χωρίς μηχανή Flutter —
οπότε εκτελείται headless σε macOS, Linux ή Windows. Κατέχει τη βάση δεδομένων,
εκτελεί τους πράκτορες και κάνει κάθε εξωτερική κλήση API· οι πελάτες απλώς
αποδίδουν.
Εκτέλεση σε Docker (έτοιμες εικόνες)
Ενότητα με τίτλο «Εκτέλεση σε Docker (έτοιμες εικόνες)»Κάθε έκδοση δημοσιεύει μια στοίβα αυτοφιλοξενίας τεσσάρων εικόνων GHCR — το
backend, τους δύο στατικούς λεπτούς πελάτες και τον προαιρετικό αναμεταδότη
σύζευξης — συν μια ξεχωριστή εικόνα cc-server-demo για τον δημόσιο κεντρικό
υπολογιστή επίδειξης. Μια εγκατάσταση αυτοφιλοξενίας δεν απαιτεί απόσπασμα
πηγαίου κώδικα. Κλειδώστε μια ετικέτα έκδοσης
(ghcr.io/samuelalev/<image>:v0.0.1-rc.1) ή ακολουθήστε το latest.
| Εικόνα | Τι είναι | Δημοσιεύει |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Το backend: βάση δεδομένων, πράκτορες, MCP, webhooks | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Ο πελάτης web (στατικό nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
Η συνοδευτική PWA για τηλέφωνο (στατικό nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Ο αναμεταδότης σύζευξης WebRTC (προαιρετικός) | -p 8788:8788 |
Ολόκληρη η στοίβα ως αρχείο compose:
services: server: image: ghcr.io/samuelalev/cc-server:latest ports: ["9030:9030"] volumes: ["cc_data:/data"] restart: unless-stopped web: image: ghcr.io/samuelalev/cc-webapp:latest ports: ["8080:8080"] restart: unless-stopped remote: image: ghcr.io/samuelalev/cc-remote:latest ports: ["8081:8080"] restart: unless-stopped signaling: image: ghcr.io/samuelalev/cc-signaling-server:latest ports: ["8788:8788"] restart: unless-stopped
volumes: cc_data:Πράγματα που αξίζει να γνωρίζετε πριν εκθέσετε οτιδήποτε από αυτά πέρα από το loopback:
-
Η εικόνα
cc-serverπεριλαμβάνειCC_SERVER_INSECURE=1(πρέπει να δεσμεύσει τη0.0.0.0για να δέχεται κίνηση στη δημοσιευμένη θύρα), κάτι που είναι ασφαλές μόνο πίσω από αντίστροφο διαμεσολαβητή που τερματίζει το TLS — Caddy, Traefik, nginx ή Cloudflare Tunnel — σε έμπιστο δίκτυο. Για να τερματίσετε το TLS εντός της διεργασίας αντ’ αυτού, προσαρτήστε ένα πιστοποιητικό και ορίστε ταCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(και μετά αφαιρέστε τοCC_SERVER_INSECURE). Όλα μπορούν να παρακαμφθούν μεdocker run -e …ή το μπλοκenvironment:του compose. -
Το
/dataείναι η μόνη κατάσταση. Οι βάσεις δεδομένων SQLite, τα μυστικά των συζευγμένων συσκευών, τα ληφθέντα μοντέλα και ο ήχος των συσκέψεων ζουν όλα στον τόμο — δημιουργήστε αντίγραφο ασφαλείας του και το κοντέινερ γίνεται αναλώσιμο. -
Συζεύξτε έναν πελάτη από μέσα από την εικόνα πριν από την πρώτη σύνδεση, το αντίστοιχο σε κοντέινερ του βήματος 3:
Παράθυρο τερματικού docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Οι δύο εικόνες πελατών είναι στατικοί κεντρικοί υπολογιστές nginx — τίποτα να διαμορφώσετε κατά την εκτέλεση· η φόρμα σύνδεσης κάθε πελάτη δέχεται το URL του διακομιστή σας, το αναγνωριστικό συσκευής και το κλειδί σύζευξης. Ο αναμεταδότης σηματοδότησης χρειάζεται επίσης μόνο τη θύρα του (τα
SIGNALING_HOST/SIGNALING_PORTμπορούν να παρακαμφθούν)· είναι χωρίς κατάσταση, δεν κρατά μυστικά και αποτελεί εφεδρεία — ένα τηλέφωνο χρησιμοποιεί loopback, LAN, tailnet ή απευθείας διαδρομήwss://όταν κάποια είναι προσβάσιμη, και καταφεύγει στον αναμεταδότη μόνο όταν καμία δεν είναι. Παραλείψτε τον αν οι πελάτες σας φτάνουν πάντα απευθείας στον διακομιστή.
Το υπόλοιπο αυτού του οδηγού δημιουργεί τον διακομιστή από τον πηγαίο κώδικα· οι σημαίες και η συμπεριφορά που καλύπτει είναι οι ίδιες που τροφοδοτούν οι μεταβλητές περιβάλλοντος της εικόνας.
Προαπαιτούμενα
Ενότητα με τίτλο «Προαπαιτούμενα»- Το Dart SDK. Αυτό το αποθετήριο κλειδώνει το SDK του με το fvm, οπότε βάλτε πρόθεμα
fvmσε κάθε εντολή. - Αυτό το αποθετήριο αποσπασμένο τοπικά.
- Την εγγενή εργαλειοθήκη που χρειάζεται το σενάριο προετοιμασίας — Rust/
cargo, καθώς καιmeson,ninja,pkg-config,gitκαι μεταγλωττιστή C++. Κάθε σενάριο δημιουργίας ονομάζει τι δεν βρίσκει και πώς να το εγκαταστήσετε. - Έναν προσβάσιμο κεντρικό υπολογιστή: loopback για τοπική χρήση, ή διεύθυνση LAN/δημόσια με TLS για απομακρυσμένους πελάτες.
Βήμα 1: Προετοιμάστε τις εγγενείς βιβλιοθήκες
Ενότητα με τίτλο «Βήμα 1: Προετοιμάστε τις εγγενείς βιβλιοθήκες»Οι εγγενείς βιβλιοθήκες είναι υποχρεωτικές — δεν υπάρχει υποβαθμισμένη λειτουργία. Δημιουργήστε τις από τη ρίζα του αποθετηρίου πριν από οτιδήποτε άλλο:
scripts/natives/build_natives.shΑυτό δημιουργεί τα rift, fff, το tree-sitter μαζί με τις γραμματικές του, τα
aec, lame, ccpty, cc_watcher, cc_inference και το εγγενές SAML στον
κατάλογο build/natives/. Το hook δημιουργίας του cc_server επανεκπέμπει ό,τι
έχει προετοιμαστεί εκεί μέσα στο πακέτο, οπότε η παράλειψη αυτού του βήματος είτε
αποτυγχάνει τη δημιουργία εντελώς είτε — με τη δίοδο διαφυγής παρακάτω — παράγει
ένα δυαδικό του οποίου ο προέλεγχος εκκίνησης αρνείται να ξεκινήσει και ονομάζει
τη βιβλιοθήκη που λείπει.
Βήμα 2: Δημιουργήστε το δυαδικό
Ενότητα με τίτλο «Βήμα 2: Δημιουργήστε το δυαδικό»cd apps/cc_serverfvm dart build cliΤο πακέτο συνοδεύει το δυαδικό με τη libsqlite3 και τις προετοιμασμένες εγγενείς
βιβλιοθήκες — δεν χρειάζεται SQLite του συστήματος ούτε μηχανή Flutter. Το
εκτελέσιμο καταλήγει στο ./build/cli/<os_arch>/bundle/bin/cc_server.
Βήμα 3: Συζεύξτε έναν πελάτη πριν από την πρώτη εκκίνηση
Ενότητα με τίτλο «Βήμα 3: Συζεύξτε έναν πελάτη πριν από την πρώτη εκκίνηση»Ένας φρέσκος κατάλογος δεδομένων δεν έχει συζευγμένη συσκευή ούτε προκοινόχρηστο
κλειδί, οπότε το αίτημα κλειδιού σύζευξης ενός πελάτη δεν μπορεί ακόμη να
ικανοποιηθεί. Εκδώστε ένα με την υποεντολή pair. Γράφει απευθείας τα global.db
και secrets.json· ένας διακομιστής που σερβίρει ήδη αυτόν τον κατάλογο δεδομένων
αναλαμβάνει τη νέα συσκευή χωρίς επανεκκίνηση:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Εκτυπώνει τρεις τιμές για επικόλληση στη φόρμα σύνδεσης ενός πελάτη:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Χρήσιμες σημαίες: --device (προεπιλογή web-client· το αναγνωριστικό επιλέγει
και το επίπεδο της συσκευής — desktop, ios, android, οτιδήποτε άλλο είναι
πελάτης web), --label (προεπιλέγεται το όνομα της πλατφόρμας συν το όνομα
κεντρικού υπολογιστή αυτού του μηχανήματος), --host (ο κεντρικός υπολογιστής που
εκτυπώνεται στο URL, αφού το loopback δεν είναι προσβάσιμο από άλλο μηχάνημα) και
--client-url. Η εκ νέου εκτέλεση του pair εναλλάσσει το κλειδί αυτής της
συσκευής και ρίχνει τις ζωντανές συνεδρίες της. Η σύζευξη δεν δημιουργεί ποτέ χώρο
εργασίας: η ροή αρχικής ρύθμισης του πελάτη που συνδέεται ονομάζει και δημιουργεί
τον πρώτο.
Με το --client-url εκτυπώνει επίσης έναν κωδικό QR σαρώσιμο από τερματικό που
ανοίγει τον πελάτη web ήδη συμπληρωμένο:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030 \ --bind any --host 192.168.1.42 --client-url https://app.usectrl.devΈνα διαπιστευτήριο που εκδόθηκε από το cc_server pair δεν φέρει καμία λήξη·
ένα που εκδόθηκε στην εφαρμογή λήγει πάντα μετά από 30 ημέρες. Ανακαλέστε μια
συσκευή που εκδόθηκε από το CLI από τις Ρυθμίσεις → Εσείς → Οι συσκευές σας
όταν τελειώσετε μαζί της.
Βήμα 4: Εκκινήστε τον διακομιστή
Ενότητα με τίτλο «Βήμα 4: Εκκινήστε τον διακομιστή»Στο loopback — η προεπιλογή, και το μόνο που χρειάζεστε για πελάτη στο ίδιο μηχάνημα:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Για να τον προσεγγίσετε από άλλο μηχάνημα, δεσμεύστε κάθε διεπαφή. Μια δέσμευση
εκτός loopback χωρίς TLS απορρίπτεται κατά την εκκίνηση (Refusing to bind non-loopback address … without TLS), οπότε δώστε ένα πιστοποιητικό:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem \ --public-url wss://server.example:9030/rpcΉ τερματίστε το TLS σε έναν αντίστροφο διαμεσολαβητή σε έμπιστο ιδιωτικό δίκτυο και επιλέξτε δέσμευση απλού κειμένου πίσω από αυτόν:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpcΤο --insecure αγνοείται όταν έχουν οριστεί και το --tls-cert και το
--tls-key — το TLS υπερισχύει πάντα. Ο διακομιστής ανακοινώνει την κατάσταση
απλού κειμένου ως insecure: true στο GET /healthz και οι πελάτες επισημαίνουν
μια τέτοια σύνδεση ως μη ασφαλή.
Ο διακομιστής εκτελείται μέχρι τα SIGINT/SIGTERM και μετά τερματίζεται καθαρά.
Βήμα 5: Συνδέστε έναν πελάτη
Ενότητα με τίτλο «Βήμα 5: Συνδέστε έναν πελάτη»Στρέψτε έναν πελάτη στο URL του διακομιστή και στο κλειδί σύζευξης του βήματος 3:
- Εφαρμογή υπολογιστή: στην οθόνη πρώτης εκτέλεσης (Πώς να εκτελείται το Control Center;) συμπληρώστε τα πεδία σύνδεσης αντί για Εκτέλεση σε αυτή την εφαρμογή, ή προσθέστε τον διακομιστή αργότερα στις Ρυθμίσεις → Διακομιστής → Σύνδεση και κατάσταση. Δείτε Σύνδεση σε απομακρυσμένο διακομιστή.
- Πελάτης web: ανοίξτε το app.usectrl.dev (ή το δικό σας αντίγραφο του build web) και εισαγάγετε το URL του διακομιστή, το αναγνωριστικό συσκευής και το κλειδί σύζευξης.
- Τηλέφωνο: συζεύξτε την εφαρμογή Remote από έναν πελάτη που εκτελείται — δείτε Σύζευξη συσκευής.
Βήμα 6: Συνδέστε ένα Google Calendar (προαιρετικό)
Ενότητα με τίτλο «Βήμα 6: Συνδέστε ένα Google Calendar (προαιρετικό)»Για να συγχρονίσετε το ημερολόγιο ενός χώρου εργασίας χωρίς συνδεδεμένο γραφικό περιβάλλον, χρησιμοποιήστε τη ροή κωδικού συσκευής:
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \ ./build/cli/<os_arch>/bundle/bin/cc_server calendar connect \ --data-dir ./data --workspace <workspace-id>Εκτυπώνει έναν κωδικό και ένα URL για έγκριση σε άλλη συσκευή, αποθηκεύει το
refresh token στην πλευρά του διακομιστή και τερματίζεται. Ένα build από πηγαίο
κώδικα δεν περιλαμβάνει πελάτη Google, οπότε οι μεταβλητές περιβάλλοντος id και
secret είναι υποχρεωτικές — δεν υπάρχει σημαία --google-client-id. Δείτε
Σύνδεση Google Calendar.
Ρύθμιση
Ενότητα με τίτλο «Ρύθμιση»Οι σημαίες που χρησιμοποιήθηκαν παραπάνω είναι αυτές που χρειάζεται μια πρώτη
εγκατάσταση. Η πλήρης επιφάνεια — 23 ζεύγη σημαιών και μεταβλητών περιβάλλοντος,
οι τέσσερις υποεντολές και η διάταξη του καταλόγου δεδομένων — βρίσκεται στην
αναφορά CLI του cc_server.
Οι τέσσερις που είναι πιθανότερο να χρειαστείτε:
| Σημαία | Προεπιλογή | Έννοια |
|---|---|---|
--data-dir |
ο κατάλογος δεδομένων εφαρμογών του χρήστη του συστήματος | Βάσεις δεδομένων, μυστικά, μοντέλα και προσωρινά αποθηκευμένα πολυμέσα |
--port |
9030 |
Θύρα TCP (0 = εφήμερη) |
--bind |
loopback |
loopback, ή any για κάθε διεπαφή (απαιτεί TLS ή --insecure) |
--public-url |
προκύπτει από τη δέσμευση | Το URL RPC που ανακοινώνεται στους συζευγμένους πελάτες. Ορίστε το ρητά πίσω από διαμεσολαβητή, NAT ή σήραγγα |
Ο προεπιλεγμένος κατάλογος δεδομένων είναι ο
~/Library/Application Support/control-center σε macOS, ο %APPDATA%\control-center
σε Windows και ο $XDG_DATA_HOME/control-center (αλλιώς
~/.local/share/control-center) αλλού. Ένα .cc_server σχετικό με τον τρέχοντα
κατάλογο εργασίας χρησιμοποιείται μόνο όταν δεν επιλύεται κατάλογος home ή
δεδομένων εφαρμογών.
Τι σερβίρει ο διακομιστής
Ενότητα με τίτλο «Τι σερβίρει ο διακομιστής»Ο cc_server είναι ολόκληρη η επιφάνεια του προϊόντος, όχι υποσύνολό της: το
μονοπάτι δεδομένων repo-RPC και οι συνδρομές, το τελικό σημείο εργαλείων MCP στο
POST /mcp και στο GET /sse στην ίδια θύρα, τα εισερχόμενα webhooks, οι
διαμεσολαβητές πολυμέσων και γραμματοσειρών, οι επιστροφές κλήσεων ενιαίας
σύνδεσης, το πρωτόκολλο μίσθωσης του στόλου, η ανάκτηση RSS στην πλευρά του
διακομιστή σε πρόγραμμα 30 λεπτών και η αναζήτηση διανυσμάτων (η επέκταση
sqlite_vector καταχωρίζεται ως αυτόματη επέκταση καθολικής εμβέλειας της
διεργασίας, υποβαθμιζόμενη σε αναζήτηση πλήρους κειμένου μόνο όπου η επέκταση δεν
είναι διαθέσιμη).
Ο dispatcher είναι χωρίς κατάσταση: δεν υπάρχει δέσμευση χώρου εργασίας ανά
συνεδρία. Κάθε κλήση με εμβέλεια χώρου εργασίας μεταφέρει το δικό της
workspace_id και η πρόσβαση κρίνεται από τη συμμετοχή και τον ρόλο του καλούντος
στον χώρο εργασίας — όχι από την κατοχή κλειδιού σύζευξης.
Δύο πράγματα που πρέπει να γνωρίζετε πριν εκθέσετε τη θύρα πέρα από το loopback:
- Το MCP αποτυγχάνει κλειστά εκτός κεντρικού υπολογιστή. Μια επιφάνεια MCP χωρίς token απαντά μόνο στο loopback. Η δέσμευση
anyδεν τη διευρύνει — ένα αίτημα εκτός κεντρικού υπολογιστή απορρίπτεται με «MCP requires a bearer token to answer non-loopback clients» μέχρι να διαμορφώσετε ένα (mcp.setToken, ή Ρυθμίσεις → Διακομιστής → Διακομιστές MCP). - Το
GET /healthzείναι χωρίς ταυτοποίηση εκ σχεδιασμού, με CORS μπαλαντέρ, και δημοσιεύει το αναγνωριστικό, το όνομα, το αποτύπωμα ταυτότητας και την έκδοση build του διακομιστή. Οι πελάτες χρειάζονται το αποτύπωμα για να καρφιτσώσουν τον διακομιστή, οπότε αυτό είναι σκόπιμο — σημαίνει όμως ότι οποιοσδήποτε προσβάσιμοςcc_serverαποκαλύπτει τόσα σε όποιον ρωτήσει.