Aller au contenu
CADCAMFUN
Docs

Documentation

Compagnon mobile

Un client iOS pour un ordinateur de bureau couplé, avec épinglage de certificat, révision de projet et sessions d'assistant partagé.

Traduit automatiquement de l'anglais. Voir l'original en anglais

Plateforme et capacités

apps/mobile est une application Expo SDK 57 utilisant React Native 0.86.3, React 19.2, Expo Router, NativeWind, Reanimated et Gesture Handler. Son transport réseau épinglé pris en charge est implémenté dans Swift par le local companion-net module. L'identifiant du bundle iOS est com.cadcamfun.mobile.

Le téléphone lit les projets, examine l'historique et les demandes d'extraction, répartit les flux de travail, reçoit les activités et interagit avec les sessions d'assistant exécutées sur le bureau couplé. Le bureau continue de posséder la base de données, le calcul de la géométrie, les informations d'identification du fournisseur d'IA et l'exécution du flux de travail. Un bureau accessible et en cours d’exécution est requis pour ces opérations.

Utiliser une version iOS native

Expo Go n'inclut pas companion-net et ne peut pas se connecter à un ordinateur de bureau couplé. Les requêtes natives échouent lorsque le module d’épinglage n’est pas disponible. La solution de secours pour le développement Web utilise la récupération du navigateur et le stockage local ; il ne fournit pas d’épinglage de certificat natif.

Structure de la candidature

Expo Router sépare les écrans de connexion des onglets d'application authentifiés. app/connect.tsx gère l'entrée d'appairage, app/pair.tsx accepte les liens profonds, et app/(app) contient les projets, l'assistant, l'activité et les paramètres. Les écrans du projet incluent des panneaux de présentation/historique/pull/workflow, les détails de la validation et l'examen des demandes d'extraction.

  • components/: contrôles réutilisables, panneaux de projet, transcription de l'assistant et interface utilisateur de connexion.
  • lib/client.ts: client typé sur un transport injecté ; Les types d'API sont importés sans le runtime du serveur.
  • lib/pairing.ts, native.ts, et storage.ts: validation du couplage, sélection du transport et informations d'identification persistantes.
  • lib/sse.ts, live-events.ts, et chat-log.ts: analyse du flux, abonnements en direct et état de la transcription.
  • modules/companion-net/: Module Expo et implémentation HTTPS épinglée par Swift.

Portée du transport et de la passerelle

La passerelle compagnon est distincte de l'écouteur de bouclage du sidecar. Il est désactivé par défaut. L'activer démarre un serveur HTTPS sur 0.0.0.0, en utilisant le port 8443, sauf si un autre port valide est sélectionné. Le service conserve son état activé et le reprend après le démarrage du sidecar. Le pare-feu du bureau et l'itinéraire réseau doivent permettre au téléphone d'atteindre cet auditeur.

Le téléphone envoie un jeton d'appareil révocable. La passerelle stocke son hachage SHA-256, vérifie la méthode/le chemin de requête par rapport à une liste verte et transmet les requêtes acceptées à l'API de bouclage à l'aide du jeton de bureau. Le téléphone ne reçoit pas ce jeton de lancement. Une authentification non valide renvoie 401, les routes refusées renvoient 403, une authentification échouée répétée peut renvoyer 429 et une indisponible en amont renvoie 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'accès au périphérique inclut les opérations d'écriture

La passerelle autorise actuellement les demandes de validation, de branchement, d'extraction et de restauration de contrôle de version, ainsi que la révision et la fusion des demandes d'extraction. Les jetons de périphérique sont limités à la stratégie de routage de la passerelle ; il ne s'agit pas d'un rôle en lecture seule ni d'une restriction par projet. Révoquer un téléphone perdu ou non fiable dans les paramètres du compagnon de bureau.

La passerelle limite les tentatives d'authentification infructueuses : après dix tentatives infructueuses de support à partir d'une adresse IP dans un délai de 60 secondes, les autres requêtes provenant de cette adresse reçoivent HTTP 429 jusqu'à l'expiration de la fenêtre (apps/sidecar/src/services/companion-gateway.ts).

Sessions d'assistant et messages hors ligne

Le compagnon envoie des demandes de chat à POST /api/ai/chat/stream et analyse les événements envoyés par le serveur. Un identifiant de session permet la poursuite de la conversation sur le bureau. Le client peut diriger ou mettre en file d'attente des messages, interrompre un tour, répondre à des questions et répondre aux demandes d'autorisation. Configurez le fournisseur de modèles sur le bureau ; le téléphone interroge l'état de l'IA avant utilisation.

Si un flux se termine sans terminal done ou error trame et n'a pas été annulée, le client signale une connexion incomplète. Le transport natif ferme son handle de flux en cas d’annulation et d’achèvement. Le décodage natif préserve les scalaires UTF-8 incomplets entre les morceaux d'octets.

Les messages de l'assistant qui ne peuvent pas être envoyés peuvent entrer dans une file d'attente persistante. Il conserve au maximum 50 entrées, supprimant les plus anciennes lorsqu'elles sont pleines, et réessaye au premier plan et à la récupération de connectivité. Les entrées échouées restent en file d’attente. Cette file d'attente stocke les messages pour une exécution ultérieure ; il ne s'agit pas d'une copie hors ligne de la géométrie du projet ou d'un environnement d'exécution d'IA hors ligne.

Construire et exécuter

Depuis la racine du référentiel
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

La commande build exporte le bundle iOS JavaScript vers apps/mobile/dist; il ne produit pas d'IPA. Les commandes d'exécution iOS nécessitent macOS, Xcode et CocoaPods. L'installation de l'appareil nécessite également un appareil de confiance, le mode développeur et une équipe de signature Apple configurée pour le projet Xcode généré. native:generate exécute la préversion Expo pour iOS sans installer de pods. Pour le travail quotidien, start (alias dev) exécute le bundler de clients de développement Expo, ios:dev le démarre sur localhost et ouvre le simulateur iOS, ios:build compile l'application de débogage sans démarrer de bundler, et web démarre la cible Web Expo. Le test le script s'exécute bun test test à l'intérieur apps/mobile.

.github/workflows/ci.yml définit la vérification du type compagnon, les tests logiques et l'exportation JavaScript. .github/workflows/ios.yml génère le projet Xcode, crée une application de simulation de version non signée, l'associe à un sidecar en direct, vérifie la liste des projets authentifiés et capture une capture d'écran. Ces vérifications configurées n’établissent pas l’acceptation du périphérique physique, de la signature, de TestFlight ou du fournisseur réel.

Sécurité du stockage et des appareils

Sur iOS natif, les informations d'identification de couplage sont stockées avec Expo SecureStore. L'entrée d'appariement utilise WHEN_UNLOCKED_THIS_DEVICE_ONLY. Les entrées de file d'attente hors ligne et les marqueurs vus en session utilisent également SecureStore. La solution de secours du navigateur utilise le stockage local pour le développement.

L'application interroge la capacité biométrique et utilise expo-local-authentication pour l'authentification locale, avec le repli du code d'accès du système activé. L’interface utilisateur biométrique ne modifie pas les autorisations de route côté serveur de la passerelle. La révocation du périphérique est contrôlée par le bureau couplé.

Le bureau conserve son certificat de passerelle et sa clé privée dans son répertoire compagnon de données d'application ; la clé est écrite avec des autorisations réservées au propriétaire. Le remplacement de ce certificat modifie l'empreinte digitale épinglée et nécessite un nouveau couplage approuvé.

Flux de travail de revue de projet

  1. Ouvrez Projets et choisissez un projet de bureau.
  2. Inspectez son état de fonctionnement, ses branches, ses validations, ses demandes d'extraction ou ses exécutions de flux de travail.
  3. Ouvrez un commit pour examiner sa différence, ou ouvrez une pull request pour examiner les modifications et soumettre un verdict.
  4. Utilisez les actions de fusion/fermeture ou de répartition de flux de travail disponibles lorsque cela est approprié pour le projet.
  5. Ouvrez l'Assistant avec le contexte de projet sélectionné pour continuer ou démarrer une session IA.

Toutes les modifications s'exécutent sur le bureau. Une interruption du réseau, une autorisation révoquée ou un bureau arrêté empêche le nouveau fonctionnement du serveur ; Les messages de l'assistant mis en file d'attente localement sont réessayés ultérieurement.

Interface client

CompanionClient accepte un 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.

Les échecs JSON deviennent CompanionError avec un statut et un message. Les discussions en streaming et les événements en direct utilisent l'analyseur SSE partagé afin que les limites arbitraires des fragments de réseau ne deviennent pas des limites d'événements d'application. Les tests injectent des transports sans importer de modules natifs ni exécuter de simulateur.

Associer un téléphone

  1. Sur le bureau, ouvrez Paramètres et son panneau compagnon Mobile, ou /settings/companionet allumez la passerelle.
  2. Créez un couplage d'appareil nommé et affichez le code QR. Le lien contient des hôtes HTTPS candidats, un jeton d'appareil et l'empreinte digitale du certificat.
  3. Sur iOS, scannez le code QR ou collez le cadcamfun://pair lien. Autorisez l’accès au réseau local lorsque vous y êtes invité.
  4. L'application valide le lien, fait la course avec les candidats hôtes annoncés et conserve la première connexion santé réussie.
  5. Confirmez que l'appareil apparaît dans les paramètres du bureau. Utilisez l'action de révocation du bureau pour supprimer son accès.

Les candidats hôtes incluent des adresses IPv privées4 et de réseau superposé appropriées ; la passerelle annonce au plus six adresses découvertes. L'écouteur actuel est IPv4, donc les adresses IPv6 découvertes ne sont pas annoncées. Un VPN ou un réseau superposé doit déjà fournir un routage pour une utilisation hors du réseau local ; le couplage ne crée pas de relais ou de VPN.

Épinglage du certificat

L'implémentation Swift utilise des données éphémères URLSession instances avec un délégué de confiance. Il accepte un certificat feuille uniquement lorsque le hachage SHA-256 de ses octets DER est égal à l'empreinte digitale du couplage. Les requêtes nécessitent HTTPS, les redirections sont refusées et les appelants natifs ne rétrogradent jamais silencieusement vers le transport du navigateur.

La confiance du certificat provient donc du lien d’appariement. Traitez le code QR et le lien collé comme des informations d'identification. Un lien avec une origine ou une empreinte digitale inattendue doit être remplacé via le flux de couplage du bureau plutôt que de contourner la validation TLS.

Diagnostiquer une connexion

  • Pas de transport natif : installez une version de développement ou de version iOS contenant le module local.
  • Aucun hôte joignable : vérifiez l'autorisation du réseau local, le pare-feu du bureau, l'adresse annoncée, le port de passerelle et le routage réseau.
  • 401: le jeton de l'appareil est invalide ou révoqué ; créer un nouvel accord.
  • 403: le point de terminaison se trouve en dehors de la liste verte des compagnons.
  • Incompatibilité de certificat : associez-le à nouveau avec le certificat de bureau actuel.
  • Assistant indisponible : vérifiez la configuration du fournisseur de bureau et si le sidecar est en cours d'exécution.

Paramètres du téléphone et état local

ParamètreDéfautComportement
ApparenceSystèmeChoisissez Système, Clair ou Sombre. Le système suit iOS jusqu'à ce qu'il soit remplacé.
HaptiqueActivéLes graduations de sélection et les retours de réussite/erreur ont des bascules distinctes.
Verrouillage de l'identification facialeDésactivéL’activation nécessite des données biométriques disponibles et enregistrées et une authentification système réussie.
Verrouiller l'arrière-planActivéLorsque le verrouillage biométrique est activé, le passage en mode inactif/en arrière-plan verrouille l'application couplée.
Connexion au bureauAppairage actuelAffiche l'adresse et le préfixe de l'empreinte digitale ; appuyer sur la ligne du bureau revérifie la connectivité.
Messages en file d'attenteZéroAffiche les messages de l'assistant en attente lorsque le bureau est inaccessible.

Les préférences de l'interface utilisateur se trouvent dans AsyncStorage sous cadcamfun.ui.v1; les informations d'identification de couplage, les messages en file d'attente et les marqueurs de session vue utilisent SecureStore. Le magasin d'interface utilisateur mémorise le projet sélectionné et la dernière session par projet pour un bureau couplé. La modification de l'identité du bureau efface le mappage projet/session mémorisé afin qu'il ne soit pas réutilisé sur un serveur non lié.

Le coordinateur de verrouillage ignore les écrans de démarrage et de connexion et affiche une superposition de déverrouillage en plein écran pour une application couplée. Il ne suspend pas les sessions côté serveur et ne révoque pas un jeton. Le dissociation supprime le couplage enregistré du téléphone et revient à Connect ; la révocation du bureau est l'action distincte qui empêche le jeton de s'authentifier à nouveau.

Exemple d'administration de passerelle

Ces requêtes s'exécutent sur l'API de bouclage du bureau avec son jeton de lancement, et non sur la passerelle téléphonique. Utilisez une instance de développement isolée. Remplacez l'exemple de port par le port de son événement prêt et fournissez le jeton de ce processus.

Inspecter et activer une passerelle de développement
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 réponse d'état contient enabled, un nullable port, un nullable fingerprint, la suggestion host, et devices. Le service accepte les ports explicites de 1024 à 65535. Un port déjà utilisé ne parvient pas à démarrer l'écouteur ; choisissez un autre port et régénérez l’adresse d’appairage.

Créer un couplage d'appareils nommé
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"}'

Remplacez l'exemple d'hôte par une adresse vers laquelle le téléphone peut être acheminé. La création réussie du couplage renvoie HTTP 201 avec un appareil id et un justificatif link. Le nom tronqué doit contenir 1–60 caractères. Scannez/collez ce lien en privé ; ne le copiez pas dans un rapport de bug. La création du jeton n'active pas automatiquement la passerelle.

Pour supprimer l'accès, envoyez DELETE /api/companion/devices/<id> en utilisant l'autorisation du bureau. Pour arrêter tout nouveau trafic de passerelle, envoyez POST /api/companion/disable. Les hachages des appareils sont vérifiés à chaque demande, de sorte que les jetons révoqués sont refusés lors des demandes suivantes.

Récupération sans perte de contexte

  1. Appuyez sur la ligne de connexion au bureau dans Paramètres pour réessayer l'état des hôtes annoncés.
  2. Si un seul chemin réseau échoue, vérifiez le bon itinéraire Wi-Fi/hotspot/VPN et régénérez un code QR après les changements d'adresse du bureau.
  3. Si l'autorisation échoue, révoquez l'appareil obsolète sur le bureau et créez un nouveau couplage.
  4. Si seul un flux d'assistant échoue, rouvrez la session de projet et inspectez son état avant de renvoyer la même instruction.
  5. Inspectez le nombre de messages en file d’attente avant de soumettre une invite en double ; les opérations en file d’attente réessayent plus tard.

La file d'attente hors ligne a une rétention limitée et relit chaque opération en attente via une nouvelle demande de discussion portant l'identifiant de session stocké lorsqu'il est disponible. Il ne s’agit pas d’une garantie de livraison unique. Une interruption du réseau après l'exécution du serveur peut laisser le client incertain quant à l'achèvement ; inspectez l’état du projet/de la session résultant avant de répéter une modification.

Ancres de mise en œuvre : app/(app)/settings.tsx, components/layout/AppLockCoordinator.tsx, lib/store.ts, lib/server.tsx, et lib/offline-queue.ts.

Liste verte de la passerelle

Le téléphone communique avec le bureau uniquement via la passerelle compagnon, qui admet cet ensemble fixe de routes et les transmet à l'API de bouclage :

MéthodesModèle de cheminBut
GET/api/healthVérification de l'accessibilité.
GET/api/projects, /api/projects/:idListe et en-tête du projet.
OBTENIR, POSTER/api/projects/:id/vcs/* (sauf remote, push, pull), /pulls/*, /actions/*Historique, demandes d'extraction, révisions et exécutions de flux de travail. La synchronisation GitHub reste sur le bureau car elle nécessite le jeton GitHub du propriétaire.
GET/api/projects/:id/eventsFlux SSE en direct de l'historique, du flux de travail et de l'activité de l'assistant ; le seul canal push du téléphone.
OBTENIR, PUBLIER, METTRE, SUPPRIMER/api/notifications, /mark-all-read, /:idLisez, marquez comme lues et supprimez les notifications.
GET/api/ai/status, /models, /agentsAssistante découverte.
POST/api/ai/chat/stream, chat/abort, chat/queue, permission/reply, sessions/state, sessions/controlSéances d'assistants.

Étant donné que la liste est corrigée dans le sidecar, une fonctionnalité qui nécessite un autre itinéraire (par exemple le téléchargement de fichiers ou le push GitHub) est une fonctionnalité réservée au bureau jusqu'à ce que la liste change.

Ce que stocke le téléphone

ArticleStockageRemarques
Origine(s) de la passerelleSecureStoreL'hôte préféré et les remplaçants du lien d'appariement.
Jeton d'appareilBanque sécurisée, WHEN_UNLOCKED_THIS_DEVICE_ONLYNe quitte jamais l'appareil sauf en tant que support vers la passerelle.
Empreinte digitale du certificatSecureStorePar rapport au certificat de la passerelle à chaque connexion.
File d'attente hors ligne, marqueurs de sessionSecureStoreMessages rédigés hors ligne et dernier état des sessions consultées.

Dans une version de développement de navigateur, les mêmes données reviennent au stockage local, qui n'est pas crypté. Utilisez-le uniquement avec des accords jetables.

Écrans

Fichier d'itinéraireÉcran
app/index.tsxEntrée : pas d'appairage → l'écran d'appairage ; jumelé → projets
app/connect.tsx, app/pair.tsxAppairage : scannez le code QR avec l'appareil photo ou collez le lien
app/(app)/projects/index.tsxListe des projets
app/(app)/projects/[id].tsxUn projet
app/(app)/projects/[id]/commit/[oid].tsxUn commit et ses modifications
app/(app)/projects/[id]/pulls/[number].tsxUne pull request : examiner et fusionner
app/(app)/assistant.tsxChat avec l'assistant
app/(app)/activity.tsxActivité en direct
app/(app)/settings.tsxParamètres de connexion et de l'appareil

Les routes utilisent les conventions de fichiers Expo Router : (app) est un groupe qui partage une mise en page sans ajouter de segment d'URL, et [id] est un paramètre.

File d'attente de l'assistant hors ligne

Lorsque le bureau n'est pas accessible, un message saisi dans l'assistant est mis en file d'attente sur le téléphone au lieu d'être perdu :

RègleValeur
OùSecureStore, pour qu'une application supprimée conserve la file d'attente
Ce qui est stocképrojectId, text, facultatif sessionId, agent, mode (général, cad, cam, gcode, parcours d'outil ; général par défaut) et queuedAt
Capacité50 entrées ; les plus âgés sont abandonnés en premier
Quand il s'écouleLorsque l'application revient au premier plan avec une association stockée
CommentChaque entrée ouvre un nouveau tour de streaming et se lit jusqu'à ce que done; un error un événement ou une transition en arrière-plan le maintient en file d'attente
RetourUn toast : "Message en file d'attente envoyé" ou "N messages en file d'attente envoyés"

Seuls les échecs de connectivité mettent un message en file d'attente. Un envoi est considéré comme hors ligne lorsque le client signale l'état 0 ou que le texte d'erreur mentionne une panne de réseau, un délai d'attente, une connexion refusée ou similaire ; Les erreurs HTTP et commerciales (« la demande à… a échoué avec… ») sont affichées au lieu d'être mises en file d'attente.

En 3D

Mobile et sidecar Faites glisser vers l'orbite · faites défiler pour zoomer · faites glisser vers la droite pour effectuer un panoramique
Processes at run time. The Tauri shell spawns the sidecar and waits for its {”event”:”ready”,”port”:N} line on stdout (sidecar.rs); the webview then talks HTTP to 127.0.0.1 on that port with the bearer token. The sidecar owns the SQLite database, the embedded nikcli AI host (CADCAMFUN_AI_HOST=nikcli, the default) and plugins; the mobile app reaches it through companion pairing.