Documentazione
Compagno mobile
Un client iOS per un desktop associato, con aggiunta di certificati, revisione del progetto e sessioni di assistente condivise.
Tradotto automaticamente dall'inglese. Vedi l'originale in inglese
Piattaforma e capacità
apps/mobile è un'applicazione Expo SDK 57 che utilizza React Native 0.86.3, React 19.2, Expo Router, NativeWind, Reanimated e Gesture Handler. Il trasporto di rete bloccato supportato è implementato in Swift dal locale companion-net modulo. L'identificatore del bundle iOS è com.cadcamfun.mobile.
Il telefono legge progetti, esamina la cronologia e le richieste pull, invia flussi di lavoro, riceve attività e interagisce con le sessioni dell'assistente in esecuzione sul desktop associato. Il desktop continua a possedere il database, il calcolo della geometria, le credenziali del fornitore di intelligenza artificiale e l'esecuzione del flusso di lavoro. Per tali operazioni è necessario un desktop raggiungibile e funzionante.
Utilizza una build iOS nativa
Expo Go non include companion-net e non è possibile connettersi a un desktop associato. Le richieste native falliscono quando il modulo di blocco non è disponibile. Il fallback dello sviluppo web utilizza il recupero del browser e l'archiviazione locale; non fornisce il blocco del certificato nativo.
Struttura dell'applicazione
Expo Router separa le schermate di connessione dalle schede delle applicazioni autenticate. app/connect.tsx gestisce l'input di abbinamento, app/pair.tsx accetta collegamenti diretti e app/(app) contiene Progetti, Assistente, Attività e Impostazioni. Le schermate del progetto includono pannelli di panoramica/cronologia/pull/flusso di lavoro, dettagli di commit e revisione delle richieste pull.
components/: controlli riutilizzabili, pannelli di progetto, trascrizione dell'assistente e interfaccia utente di connessione.lib/client.ts: client digitato su un trasporto iniettato; I tipi API vengono importati senza il runtime del server.lib/pairing.ts,native.ts, estorage.ts: convalida dell'accoppiamento, selezione del trasporto e credenziali persistenti.lib/sse.ts,live-events.ts, echat-log.ts: analisi dello streaming, abbonamenti live e stato della trascrizione.modules/companion-net/: Modulo Expo e implementazione HTTPS bloccata da Swift.
Ambito di trasporto e gateway
Il gateway complementare è separato dal listener di loopback del sidecar. È disattivato per impostazione predefinita. Abilitandolo si avvia un server HTTPS 0.0.0.0, utilizzando la porta 8443 a meno che non venga selezionata un'altra porta valida. Il servizio mantiene il suo stato abilitato e lo riprende dopo l'avvio del sidecar. Il firewall del desktop e il percorso di rete devono consentire al telefono di raggiungere questo ascoltatore.
Il telefono invia un token del dispositivo revocabile. Il gateway archivia il proprio hash SHA-256, controlla il metodo/percorso della richiesta rispetto a un elenco consentito e inoltra le richieste accettate all'API di loopback utilizzando il token desktop. Il telefono non riceve il token di avvio. L'autenticazione non valida restituisce 401, le rotte negate restituiscono 403, l'autenticazione ripetuta non riuscita può restituire 429 e un upstream non disponibile restituisce 502.
Allowed families include project reads; version-control, pull-request, and workflow endpoints; project events; notifications; assistant status/models/agents; streaming chat; queue/abort; permissions; and session state/control. Files, credentials, plugins, billing, gateway administration, and GitHub remote/push/pull endpoints are excluded.
L'accesso al dispositivo include le operazioni di scrittura
Il gateway attualmente consente richieste di commit, branch, checkout e ripristino del controllo della versione, nonché la revisione e l'unione delle richieste pull. I token del dispositivo hanno come ambito la policy di instradamento del gateway; non sono un ruolo di sola lettura o una restrizione per progetto. Revoca un telefono smarrito o non attendibile nelle impostazioni del compagno desktop.
Il gateway limita i tentativi di autenticazione non riusciti: dopo dieci tentativi di portante falliti da un indirizzo IP entro 60 secondi, ulteriori richieste da quell'indirizzo ricevono HTTP 429 fino alla scadenza della finestra (apps/sidecar/src/services/companion-gateway.ts).
Sessioni dell'assistente e messaggi offline
Il compagno invia richieste di chat a POST /api/ai/chat/stream e analizza gli eventi inviati dal server. Un identificatore di sessione consente la continuazione della conversazione sul desktop. Il client può dirigere o accodare messaggi, interrompere una svolta, rispondere a domande e rispondere alle richieste di autorizzazione. Configurare il provider del modello sul desktop; il telefono interroga lo stato dell'AI prima dell'uso.
Se uno stream termina senza un terminale done o error frame e non è stato annullato, il client segnala una connessione incompleta. Il trasporto nativo chiude l'handle del flusso in caso di annullamento e completamento. La decodifica nativa preserva gli scalari UTF-8 incompleti tra i blocchi di byte.
I messaggi dell'assistente che non possono essere inviati possono entrare in una coda permanente. Conserva al massimo 50 voci, eliminando quelle più vecchie quando sono piene e riprova in primo piano e nel ripristino della connettività. Le voci non riuscite rimangono in coda. Questa coda memorizza i messaggi per l'esecuzione successiva; non è una copia offline della geometria del progetto o un runtime AI offline.
Costruisci e corri
bun install
bun run --cwd apps/mobile test
bun run --cwd apps/mobile typecheck
bun run --cwd apps/mobile build
bun run --cwd apps/mobile ios
bun run --cwd apps/mobile ios:release --device Il comando build esporta il bundle JavaScript iOS in apps/mobile/dist; non produce un IPA. I comandi di esecuzione iOS richiedono macOS, Xcode e CocoaPods. L'installazione del dispositivo richiede inoltre un dispositivo attendibile, la modalità sviluppatore e un team di firma Apple configurato per il progetto Xcode generato. native:generate esegue Expo prebuild per iOS senza installare pod. Per il lavoro quotidiano, start (alias dev) esegue il bundler del client di sviluppo di Expo, ios:dev lo avvia su localhost e apre il simulatore iOS, ios:build compila l'app di debug senza avviare un bundler e web avvia il web target di Expo. IL test viene eseguito lo script bun test test dentro apps/mobile.
.github/workflows/ci.yml definisce il controllo del tipo associato, i test logici e l'esportazione JavaScript. .github/workflows/ios.yml genera il progetto Xcode, crea un'app di simulazione di rilascio non firmata, la associa a un sidecar live, controlla l'elenco dei progetti autenticati e acquisisce uno screenshot. Questi controlli configurati non stabiliscono l'accettazione del dispositivo fisico, della firma, di TestFlight o del fornitore reale.
Archiviazione e sicurezza dei dispositivi
Su iOS nativo, le credenziali di abbinamento vengono archiviate con Expo SecureStore. La voce di abbinamento utilizza WHEN_UNLOCKED_THIS_DEVICE_ONLY. Anche le voci della coda offline e gli indicatori di sessione visualizzati utilizzano SecureStore. Il fallback del browser utilizza l'archiviazione locale per lo sviluppo.
L'app interroga la capacità e gli usi biometrici expo-local-authentication per l'autenticazione locale, con fallback del passcode di sistema abilitato. L'interfaccia utente biometrica non modifica le autorizzazioni del percorso lato server del gateway. La revoca del dispositivo è controllata dal desktop associato.
Il desktop conserva il certificato del gateway e la chiave privata nella directory complementare dei dati dell'applicazione; la chiave viene scritta con autorizzazioni di solo proprietario. La sostituzione del certificato modifica l'impronta digitale bloccata e richiede un nuovo accoppiamento attendibile.
Flusso di lavoro di revisione del progetto
- Apri Progetti e scegli un progetto desktop.
- Ispeziona lo stato di funzionamento, i rami, i commit, le richieste pull o le esecuzioni del flusso di lavoro.
- Apri un commit per esaminarne le differenze o apri una richiesta pull per esaminare le modifiche e inviare un verdetto.
- Utilizza le azioni di unione/chiusura o di invio del flusso di lavoro disponibili quando appropriato per il progetto.
- Apri l'Assistente con il contesto del progetto selezionato per continuare o avviare una sessione AI.
Tutte le modifiche vengono eseguite sul desktop. L'interruzione della rete, l'autorizzazione revocata o un desktop arrestato impediscono il nuovo funzionamento del server; I messaggi dell'assistente in coda locale vengono ritentati in seguito.
Interfaccia cliente
CompanionClient accetta a Transport with JSON request and text-stream methods. It exposes project reads; VCS status, history, diff, commit, branch, checkout, and restore; pull requests and reviews; workflow runs and dispatch; AI status/models/agents; session control; notifications; and project event streams.
Gli errori JSON diventano CompanionError con uno stato e un messaggio. La chat in streaming e gli eventi live utilizzano il parser SSE condiviso in modo che i limiti arbitrari dei blocchi di rete non diventino limiti degli eventi dell'applicazione. I test inseriscono trasporti senza importare moduli nativi o eseguire un simulatore.
Accoppia un telefono
- Sul desktop, apri Impostazioni e il relativo pannello Mobile, oppure
/settings/companione accendere il gateway. - Crea un accoppiamento con nome del dispositivo e visualizza il codice QR. Il collegamento contiene i candidati host HTTPS, un token del dispositivo e l'impronta digitale del certificato.
- Su iOS, scansiona il codice QR o incolla il file
cadcamfun://paircollegamento. Consenti l'accesso alla rete locale quando richiesto. - L'app convalida il collegamento, gareggia con i candidati host pubblicizzati e mantiene la prima connessione sanitaria riuscita.
- Verifica che il dispositivo venga visualizzato nelle impostazioni del desktop. Utilizza l'azione di revoca del desktop per rimuoverne l'accesso.
I candidati host includono IPv privati4 e indirizzi di rete overlay adeguati; il gateway pubblicizza al massimo sei indirizzi scoperti. Il listener corrente è IPv4, quindi gli indirizzi IPv6 rilevati non vengono pubblicizzati. Una rete VPN o overlay deve già fornire il routing da utilizzare lontano dalla rete locale; l'accoppiamento non crea un relè o una VPN.
Blocco del certificato
L'implementazione Swift utilizza effimero URLSession istanze con un delegato di fiducia. Accetta un certificato foglia solo quando l'hash SHA-256 dei suoi byte DER equivale all'impronta digitale dell'accoppiamento. Le richieste richiedono HTTPS, i reindirizzamenti vengono rifiutati e i chiamanti nativi non eseguono mai il downgrade silenzioso al trasporto del browser.
L'attendibilità del certificato deriva quindi dal collegamento di accoppiamento. Considera il codice QR e il collegamento incollato come credenziali. Un collegamento con un'origine o un'impronta digitale imprevista deve essere sostituito tramite il flusso di accoppiamento del desktop anziché ignorare la convalida TLS.
Diagnosticare una connessione
- Nessun trasporto nativo: installare uno sviluppo iOS o una build di rilascio contenente il modulo locale.
- Nessun host raggiungibile: controlla l'autorizzazione della rete locale, il firewall desktop, l'indirizzo pubblicizzato, la porta del gateway e il routing della rete.
- 401: il token del dispositivo non è valido o è stato revocato; creare un nuovo abbinamento.
- 403: l'endpoint è esterno all'elenco consentito associato.
- Mancata corrispondenza del certificato: associarlo nuovamente al certificato desktop corrente.
- Assistente non disponibile: controlla la configurazione del provider desktop e se il sidecar è in esecuzione.
Impostazioni del telefono e stato locale
| Collocamento | Predefinito | Comportamento |
|---|---|---|
| Aspetto | Sistema | Scegli Sistema, Chiaro o Scuro. Il sistema segue iOS finché non viene sovrascritto. |
| Aptica | Abilitato | I segni di spunta di selezione e il feedback di successo/errore hanno interruttori separati. |
| Blocco ID viso | Disabilitato | L'abilitazione richiede dati biometrici disponibili e registrati e un'autenticazione del sistema riuscita. |
| Blocca sullo sfondo | Abilitato | Quando il blocco biometrico è abilitato, lo spostamento su inattivo/in background blocca l'app abbinata. |
| Connessione al desktop | Associazione attuale | Mostra l'indirizzo e il prefisso dell'impronta digitale; toccando la riga del desktop si ricontrolla la connettività. |
| Messaggi in coda | Zero | Mostra i messaggi dell'assistente in sospeso mentre il desktop non è raggiungibile. |
Le preferenze dell'interfaccia utente si trovano in AsyncStorage sotto cadcamfun.ui.v1; le credenziali di associazione, i messaggi in coda e gli indicatori di sessione vista utilizzano SecureStore. L'archivio dell'interfaccia utente ricorda il progetto selezionato e l'ultima sessione per progetto per un desktop abbinato. La modifica dell'identità del desktop cancella la mappatura del progetto/sessione ricordata in modo che non venga riutilizzata su un server non correlato.
Il coordinatore del blocco salta le schermate di avvio e connessione e mostra una sovrapposizione di sblocco a schermo intero per un'app abbinata. Non sospende le sessioni lato server né revoca un token. L'annullamento dell'abbinamento rimuove l'abbinamento salvato del telefono e ritorna a Connetti; la revoca del desktop è l'azione separata che impedisce la nuova autenticazione del token.
Esempio di amministrazione del gateway
Queste richieste vengono eseguite sull'API di loopback del desktop con il relativo token di avvio, non sul gateway del telefono. Utilizza un'istanza di sviluppo isolata. Sostituisci la porta di esempio con la porta del suo evento ready e fornisci il token di quel processo.
CADCAM_URL=http://127.0.0.1:43111
CADCAM_TOKEN=local-development-token
curl --fail-with-body "$CADCAM_URL/api/companion" -H "Authorization: Bearer $CADCAM_TOKEN"
curl --fail-with-body -X POST "$CADCAM_URL/api/companion/enable" -H "Authorization: Bearer $CADCAM_TOKEN" -H 'Content-Type: application/json' -d '{"port":18443}' La risposta sullo stato contiene enabled, un nullable port, un nullable fingerprint, il suggerito host, e devices. Il servizio accetta porte esplicite da 1024 a 65535. Una porta già in uso non riesce ad avviare il listener; scegli un'altra porta e rigenera l'indirizzo di accoppiamento.
curl --fail-with-body -X POST "$CADCAM_URL/api/companion/pair" -H "Authorization: Bearer $CADCAM_TOKEN" -H 'Content-Type: application/json' -d '{"name":"Development iPhone","host":"192.168.1.20"}' Sostituisci l'host di esempio con un indirizzo a cui il telefono può instradare. La creazione dell'associazione riuscita restituisce HTTP 201 con un dispositivo id e un portatore di credenziali link. Il nome troncato deve contenere 1–60 caratteri. Scansiona/incolla il link in privato; non copiarlo in una segnalazione di bug. La creazione del token non attiva automaticamente il gateway.
Per rimuovere l'accesso, invia DELETE /api/companion/devices/<id> utilizzando l'autorizzazione desktop. Per interrompere tutto il nuovo traffico gateway, invia POST /api/companion/disable. Gli hash del dispositivo vengono controllati a ogni richiesta, quindi i token revocati vengono rifiutati nelle richieste successive.
Recupero senza perdere il contesto
- Tocca la riga della connessione desktop in Impostazioni per riprovare l'integrità con gli host pubblicizzati.
- Se solo un percorso di rete fallisce, verifica il percorso Wi-Fi/hotspot/VPN corretto e rigenera un codice QR dopo la modifica dell'indirizzo del desktop.
- Se l'autorizzazione fallisce, revoca il dispositivo obsoleto sul desktop e crea un nuovo abbinamento.
- Se solo un flusso dell'assistente ha avuto esito negativo, riapri la sessione del progetto e controllane lo stato prima di inviare nuovamente la stessa istruzione.
- Controllare il conteggio dei messaggi in coda prima di inviare una richiesta duplicata; le operazioni in coda riprovano più tardi.
La coda offline ha una conservazione limitata e riproduce ogni operazione in sospeso tramite una nuova richiesta di chat che trasporta l'identificatore di sessione memorizzato quando disponibile. Non è una garanzia di consegna esatta. Un'interruzione della rete dopo l'esecuzione del server può lasciare il client incerto sul completamento; ispezionare lo stato risultante del progetto/sessione prima di ripetere una modifica.
Ancore di implementazione: app/(app)/settings.tsx, components/layout/AppLockCoordinator.tsx, lib/store.ts, lib/server.tsx, e lib/offline-queue.ts.
Elenco consentiti del gateway
Il telefono comunica con il desktop solo tramite il gateway complementare, che ammette questo insieme fisso di percorsi e li inoltra all'API di loopback:
| Metodi | Modello del percorso | Scopo |
|---|---|---|
| GET | /api/health | Verifica di raggiungibilità. |
| GET | /api/projects, /api/projects/:id | Elenco progetti e intestazione. |
| OTTIENI, PUBBLICA | /api/projects/:id/vcs/* (tranne remote, push, pull), /pulls/*, /actions/* | Cronologia, richieste pull, revisioni ed esecuzioni del flusso di lavoro. La sincronizzazione GitHub rimane sul desktop perché necessita del token GitHub del proprietario. |
| GET | /api/projects/:id/events | Flusso SSE in tempo reale di cronologia, flusso di lavoro e attività dell'assistente; l'unico canale push del telefono. |
| OTTIENI, PUBBLICA, METTI, ELIMINA | /api/notifications, /mark-all-read, /:id | Leggi, contrassegna come letti ed elimina le notifiche. |
| GET | /api/ai/status, /models, /agents | Scoperta dell'assistente. |
| POST | /api/ai/chat/stream, chat/abort, chat/queue, permission/reply, sessions/state, sessions/control | Sessioni di assistente. |
Poiché l'elenco è fisso nel sidecar, una funzionalità che richiede un altro percorso (ad esempio il caricamento di file o il push di GitHub) è una funzionalità solo desktop finché l'elenco non cambia.
Cosa memorizza il telefono
| Articolo | Magazzinaggio | Note |
|---|---|---|
| Origini del gateway | SecureStore | L'host preferito plus si alterna dal collegamento di accoppiamento. |
| Token del dispositivo | SecureStore, WHEN_UNLOCKED_THIS_DEVICE_ONLY | Non lascia mai il dispositivo se non come intestazione portante per il gateway. |
| Impronta digitale del certificato | SecureStore | Rispetto al certificato del gateway su ogni connessione. |
| Coda offline, indicatori di sessione | SecureStore | Messaggi composti mentre sei offline e stato delle sessioni visualizzate per ultimo. |
In una build di sviluppo del browser, gli stessi dati ricadono nell'archiviazione locale, che non è crittografata. Usatelo solo con abbinamenti usa e getta.
Schermi
| File di percorso | Schermo |
|---|---|
app/index.tsx | Voce: nessun abbinamento → schermata di abbinamento; accoppiati → progetti |
app/connect.tsx, app/pair.tsx | Associazione: scansiona il codice QR con la fotocamera o incolla il collegamento |
app/(app)/projects/index.tsx | Elenco progetti |
app/(app)/projects/[id].tsx | Un progetto |
app/(app)/projects/[id]/commit/[oid].tsx | Un commit e le sue modifiche |
app/(app)/projects/[id]/pulls/[number].tsx | Una richiesta pull: revisione e unione |
app/(app)/assistant.tsx | Chat con l'assistente |
app/(app)/activity.tsx | Attività dal vivo |
app/(app)/settings.tsx | Impostazioni di connessione e dispositivo |
I percorsi utilizzano le convenzioni dei file Expo Router: (app) è un gruppo che condivide un layout senza aggiungere un segmento URL e [id] è un parametro.
Coda dell'assistente offline
Quando il desktop non è raggiungibile, un messaggio digitato nell'assistente viene accodato sul telefono invece di essere perso:
| Regola | Valore |
|---|---|
| Dove | SecureStore, quindi un'app uccisa mantiene la coda |
| Cosa viene memorizzato | projectId, text, facoltativo sessionId, agent, mode (generale, cad, cam, gcode, percorso utensile; generale predefinito) e queuedAt |
| Capacità | 50 voci; i più vecchi vengono eliminati per primi |
| Quando si scarica | Quando l'app torna in primo piano con un abbinamento memorizzato |
| Come | Ogni voce apre un nuovo turno di streaming e legge fino a done; uN error un evento o una transizione in background lo mantiene in coda |
| Feedback | Un brindisi: "Messaggio in coda inviato" o "N messaggi in coda inviati" |
Solo gli errori di connettività accodano un messaggio. Un invio viene considerato offline quando il client segnala lo stato 0 o il testo dell'errore menziona un errore di rete, timeout, connessione rifiutata o simili; Gli errori HTTP e aziendali ("richiesta a... non riuscita con...") vengono visualizzati anziché messi in coda.