Saltar al contenido
CADCAMFUN
Documentos

Documentación

Compañero móvil

Un cliente iOS para un escritorio emparejado, con fijación de certificados, revisión de proyectos y sesiones de asistente compartidas.

Traducido automáticamente del inglés. Ver el original en inglés

Plataforma y capacidades

apps/mobile es una aplicación Expo SDK 57 que utiliza React Native 0.86.3, React 19.2, Expo Router, NativeWind, Reanimated y Gesture Handler. Su transporte de red anclado admitido es implementado en Swift por el local companion-net módulo. El identificador del paquete de iOS es com.cadcamfun.mobile.

El teléfono lee proyectos, revisa el historial y las solicitudes de extracción, envía flujos de trabajo, recibe actividad e interactúa con las sesiones del asistente que se ejecutan en el escritorio emparejado. El escritorio sigue siendo propietario de la base de datos, el cálculo de la geometría, las credenciales del proveedor de IA y la ejecución del flujo de trabajo. Se requiere un escritorio accesible y en ejecución para esas operaciones.

Utilice una compilación nativa de iOS

Expo Go no incluye companion-net y no puede conectarse a un escritorio emparejado. Las solicitudes nativas fallan cuando el módulo de fijación no está disponible. El respaldo del desarrollo web utiliza la recuperación del navegador y el almacenamiento local; no proporciona fijación de certificados nativos.

Estructura de la aplicación

Expo Router separa las pantallas de conexión de las pestañas de aplicaciones autenticadas. app/connect.tsx maneja la entrada de emparejamiento, app/pair.tsx acepta enlaces profundos, y app/(app) contiene Proyectos, Asistente, Actividad y Configuración. Las pantallas del proyecto incluyen paneles de descripción general/historial/extracción/flujo de trabajo, detalles de confirmación y revisión de solicitud de extracción.

  • components/: controles reutilizables, paneles de proyecto, transcripción del asistente y interfaz de usuario de conexión.
  • lib/client.ts: cliente escrito sobre un transporte inyectado; Los tipos de API se importan sin el tiempo de ejecución del servidor.
  • lib/pairing.ts, native.ts, y storage.ts: validación de emparejamiento, selección de transporte y credenciales persistentes.
  • lib/sse.ts, live-events.ts, y chat-log.ts: análisis de transmisiones, suscripciones en vivo y estado de transcripción.
  • modules/companion-net/: Módulo Expo e implementación HTTPS anclada en Swift.

Alcance del transporte y la puerta de enlace

La puerta de enlace complementaria está separada del oyente de loopback del sidecar. Está desactivado de forma predeterminada. Al habilitarlo se inicia un servidor HTTPS en 0.0.0.0, utilizando el puerto 8443 a menos que se seleccione otro puerto válido. El servicio mantiene su estado habilitado y lo reanuda después del inicio del sidecar. El firewall del escritorio y la ruta de red deben permitir que el teléfono llegue a este oyente.

El teléfono envía un token de dispositivo revocable. La puerta de enlace almacena su hash SHA-256, verifica el método/ruta de solicitud con una lista de permitidos y reenvía las solicitudes aceptadas a la API de bucle invertido utilizando el token de escritorio. El teléfono no recibe ese token de inicio. La autenticación no válida devuelve 401, las rutas denegadas devuelven 403, la autenticación fallida repetida puede devolver 429 y un flujo ascendente no disponible devuelve 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.

El acceso al dispositivo incluye operaciones de escritura.

Actualmente, la puerta de enlace permite solicitudes de confirmación, bifurcación, extracción y restauración de control de versiones, así como revisión y fusión de solicitudes de extracción. Los tokens de dispositivo tienen como ámbito la política de ruta de puerta de enlace; no son una función de solo lectura ni una restricción por proyecto. Revocar un teléfono perdido o que no sea de confianza en la configuración complementaria de escritorio.

La puerta de enlace limita los intentos fallidos de autenticación: después de diez intentos fallidos de portador desde una dirección IP en 60 segundos, las solicitudes adicionales de esa dirección reciben HTTP 429 hasta que expire la ventana (apps/sidecar/src/services/companion-gateway.ts).

Sesiones de asistente y mensajes sin conexión

El acompañante envía solicitudes de chat a POST /api/ai/chat/stream y analiza eventos enviados por el servidor. Un identificador de sesión permite la continuación de la conversación en el escritorio. El cliente puede dirigir o poner en cola mensajes, cancelar un turno, responder preguntas y responder a solicitudes de permiso. Configure el proveedor del modelo en el escritorio; el teléfono consulta el estado de la IA antes de usarlo.

Si una transmisión termina sin terminal done o error frame y no fue cancelado, el cliente informa una conexión incompleta. El transporte local cierra su control de flujo tras la cancelación y finalización. La descodificación nativa conserva escalares UTF-8 incompletos entre fragmentos de bytes.

Los mensajes del Asistente que no se pueden enviar pueden ingresar a una cola persistente. Retiene como máximo 50 entradas, eliminando las más antiguas cuando está llena y vuelve a intentar recuperar la conectividad y el primer plano. Las entradas fallidas permanecen en cola. Esta cola almacena mensajes para su posterior ejecución; No es una copia fuera de línea de la geometría del proyecto ni un tiempo de ejecución de IA fuera de línea.

Construir y ejecutar

Desde la raíz del repositorio
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

El comando de compilación exporta el paquete JavaScript de iOS a apps/mobile/dist; no produce una IPA. Los comandos de ejecución de iOS requieren macOS, Xcode y CocoaPods. La instalación del dispositivo también requiere un dispositivo confiable, un modo de desarrollador y un equipo de firma de Apple configurado para el proyecto Xcode generado. native:generate ejecuta la precompilación de Expo para iOS sin instalar pods. Para el trabajo diario, start (alias dev) ejecuta el paquete de cliente de desarrollo Expo, ios:dev lo inicia en localhost y abre el simulador de iOS, ios:build compila la aplicación de depuración sin iniciar un paquete, y web inicia el destino web de la Expo. El test ejecución del script bun test test adentro apps/mobile.

.github/workflows/ci.yml define la verificación de tipos complementaria, pruebas lógicas y exportación de JavaScript. .github/workflows/ios.yml genera el proyecto Xcode, crea una aplicación de simulador de lanzamiento sin firmar, la vincula con un sidecar en vivo, verifica la lista de proyectos autenticados y captura una captura de pantalla. Estas comprobaciones configuradas no establecen la aceptación del dispositivo físico, la firma, TestFlight o el proveedor real.

Seguridad del almacenamiento y del dispositivo

En iOS nativo, las credenciales de emparejamiento se almacenan en Expo SecureStore. La entrada de emparejamiento utiliza WHEN_UNLOCKED_THIS_DEVICE_ONLY. Las entradas de cola sin conexión y los marcadores de sesiones vistas también utilizan SecureStore. El respaldo del navegador utiliza almacenamiento local para el desarrollo.

La aplicación consulta la capacidad biométrica y los usos. expo-local-authentication para autenticación local, con la reserva de contraseña del sistema habilitada. La interfaz de usuario biométrica no cambia los permisos de ruta del lado del servidor de la puerta de enlace. La revocación del dispositivo está controlada por el escritorio emparejado.

El escritorio mantiene su certificado de puerta de enlace y su clave privada en el directorio complementario de datos de su aplicación; la clave está escrita con permisos exclusivos del propietario. Reemplazar ese certificado cambia la huella digital fijada y requiere un nuevo emparejamiento confiable.

Flujo de trabajo de revisión de proyectos

  1. Abra Proyectos y elija un proyecto de escritorio.
  2. Inspeccione su estado de funcionamiento, ramas, confirmaciones, solicitudes de extracción o ejecuciones de flujo de trabajo.
  3. Abra una confirmación para revisar su diferencia o abra una solicitud de extracción para revisar los cambios y enviar un veredicto.
  4. Utilice las acciones disponibles de combinación/cierre o envío de flujo de trabajo cuando sea apropiado para el proyecto.
  5. Abra el Asistente con el contexto del proyecto seleccionado para continuar o iniciar una sesión de IA.

Todos los cambios se ejecutan en el escritorio. La interrupción de la red, la autorización revocada o un escritorio detenido impiden que el nuevo servidor funcione; Los mensajes del asistente en cola local se reintentan más tarde.

Interfaz de cliente

CompanionClient acepta 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.

Los fallos JSON se convierten CompanionError con un estado y un mensaje. El chat de transmisión y los eventos en vivo utilizan el analizador SSE compartido para que los límites arbitrarios de fragmentos de red no se conviertan en límites de eventos de aplicaciones. Las pruebas inyectan transportes sin importar módulos nativos ni ejecutar un simulador.

Emparejar un teléfono

  1. En el escritorio, abra Configuración y su panel complementario Móvil, o /settings/companiony encienda la puerta de enlace.
  2. Cree un emparejamiento de dispositivos con nombre y muestre el código QR. El enlace contiene candidatos de host HTTPS, un token de dispositivo y la huella digital del certificado.
  3. En iOS, escanea el código QR o pega el cadcamfun://pair enlace. Permita el acceso a la red local cuando se le solicite.
  4. La aplicación valida el enlace, compite con los candidatos a anfitriones anunciados y mantiene la primera conexión de salud exitosa.
  5. Confirme que el dispositivo aparezca en la configuración del escritorio. Utilice la acción de revocar del escritorio para eliminar su acceso.

Los candidatos a host incluyen direcciones IPv4 privadas adecuadas y direcciones de red superpuestas; la puerta de enlace anuncia como máximo seis direcciones descubiertas. El oyente actual es IPv4, por lo que las direcciones IPv6 descubiertas no se anuncian. Una VPN o una red superpuesta ya debe proporcionar enrutamiento para su uso fuera de la red local; El emparejamiento no crea una retransmisión ni una VPN.

Fijación de certificado

La implementación de Swift utiliza efímeros. URLSession instancias con un delegado de confianza. Acepta un certificado hoja solo cuando el hash SHA-256 de sus bytes DER es igual a la huella digital del emparejamiento. Las solicitudes requieren HTTPS, las redirecciones se rechazan y las personas que llaman nativas nunca bajan silenciosamente al transporte del navegador.

Por lo tanto, la confianza del certificado proviene del enlace de emparejamiento. Trate el código QR y el enlace pegado como credenciales. Un vínculo con un origen o una huella digital inesperados debe reemplazarse a través del flujo de emparejamiento del escritorio en lugar de pasar por alto la validación TLS.

Diagnosticar una conexión

  • Sin transporte nativo: instale un desarrollo de iOS o una versión de lanzamiento que contenga el módulo local.
  • Ningún host accesible: verifique el permiso de la red local, el firewall del escritorio, la dirección anunciada, el puerto de puerta de enlace y el enrutamiento de la red.
  • 401: el token del dispositivo no es válido o está revocado; Crea una nueva pareja.
  • 403: el punto final está fuera de la lista de permitidos complementarios.
  • El certificado no coincide: emparéjelo nuevamente con el certificado de escritorio actual.
  • Asistente no disponible: verifique la configuración del proveedor de escritorio y si el sidecar se está ejecutando.

Configuración del teléfono y estado local

ConfiguraciónPor defectoComportamiento
AparienciaSistemaElija Sistema, Claro u Oscuro. El sistema sigue a iOS hasta que se anula.
hápticosActivadoLos ticks de selección y los comentarios de éxito/error tienen opciones independientes.
Bloqueo de identificación facialDesactivadoLa habilitación requiere datos biométricos registrados y disponibles y una autenticación exitosa del sistema.
Bloquear en segundo planoActivadoCuando el bloqueo biométrico está habilitado, pasar a inactivo/en segundo plano bloquea la aplicación emparejada.
Conexión de escritorioEmparejamiento actualMuestra la dirección y el prefijo de la huella digital; al tocar la fila del escritorio se vuelve a verificar la conectividad.
Mensajes en colaCeroMuestra mensajes pendientes del asistente mientras no se puede acceder al escritorio.

Las preferencias de la interfaz de usuario se encuentran en AsyncStorage en cadcamfun.ui.v1; las credenciales de emparejamiento, los mensajes en cola y los marcadores de sesiones vistas utilizan SecureStore. La tienda de UI recuerda el proyecto seleccionado y la última sesión por proyecto para un escritorio emparejado. Cambiar la identidad del escritorio borra la asignación de proyecto/sesión recordada para que no se reutilice en un servidor no relacionado.

El coordinador de bloqueo omite las pantallas de inicio y conexión y muestra una superposición de desbloqueo de pantalla completa para una aplicación emparejada. No suspende las sesiones del lado del servidor ni revoca un token. La desvinculación elimina el emparejamiento guardado del teléfono y regresa a Connect; La revocación de escritorio es la acción independiente que impide que el token se autentique nuevamente.

Ejemplo de administración de puerta de enlace

Estas solicitudes se ejecutan en la API de loopback del escritorio con su token de inicio, no en la puerta de enlace del teléfono. Utilice una instancia de desarrollo aislada. Reemplace el puerto de ejemplo con el puerto de su evento listo y proporcione el token de ese proceso.

Inspeccionar y habilitar una puerta de enlace de desarrollo
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 respuesta de estado contiene enabled, un anulable port, un anulable fingerprint, el sugerido host, y devices. El servicio acepta puertos explícitos desde 1024 hasta 65535. Un puerto que ya está en uso no puede iniciar el oyente; elija otro puerto y regenere la dirección de emparejamiento.

Crear un emparejamiento de dispositivos con nombre
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"}'

Reemplace el host de ejemplo con una dirección a la que el teléfono pueda enrutarse. La creación exitosa del emparejamiento devuelve HTTP 201 con un dispositivo id y una credencial link. El nombre recortado debe contener 1–60 caracteres. Escanee/pegue ese enlace de forma privada; no lo copie en un informe de error. La creación del token no activa automáticamente la puerta de enlace.

Para eliminar el acceso, envíe DELETE /api/companion/devices/<id> utilizando la autorización de escritorio. Para detener todo el tráfico nuevo de la puerta de enlace, envíe POST /api/companion/disable. Los hashes del dispositivo se verifican en cada solicitud, por lo que los tokens revocados se rechazan en solicitudes posteriores.

Recuperación sin perder el contexto

  1. Toque la fila de conexión de escritorio en Configuración para volver a comprobar el estado de los hosts anunciados.
  2. Si solo falla una ruta de red, verifique la ruta Wi-Fi/hotspot/VPN correcta y vuelva a generar un código QR después de que cambie la dirección del escritorio.
  3. Si la autorización falla, revoque el dispositivo obsoleto en el escritorio y cree un emparejamiento nuevo.
  4. Si solo falló una secuencia del asistente, vuelva a abrir la sesión del proyecto e inspeccione su estado antes de volver a enviar la misma instrucción.
  5. Inspeccionar el recuento de mensajes en cola antes de enviar un mensaje duplicado; las operaciones en cola vuelven a intentarlo más tarde.

La cola fuera de línea tiene retención limitada y reproduce cada operación pendiente a través de una nueva solicitud de chat que lleva el identificador de sesión almacenado cuando está disponible. No es una garantía de entrega exactamente una vez. Una caída de la red después de la ejecución del servidor puede dejar al cliente inseguro sobre la finalización; Inspeccione el estado resultante del proyecto/sesión antes de repetir un cambio.

Anclas de implementación: app/(app)/settings.tsx, components/layout/AppLockCoordinator.tsx, lib/store.ts, lib/server.tsx, y lib/offline-queue.ts.

Lista de permitidos de puerta de enlace

El teléfono se comunica con el escritorio sólo a través de la puerta de enlace complementaria, que admite este conjunto fijo de rutas y las reenvía a la API de loopback:

MétodosPatrón de rutaObjetivo
GET/api/healthComprobación de accesibilidad.
GET/api/projects, /api/projects/:idLista de proyectos y encabezado.
OBTENER, PUBLICAR/api/projects/:id/vcs/* (excepto remote, push, pull), /pulls/*, /actions/*Historial, solicitudes de extracción, revisiones y ejecuciones de flujo de trabajo. La sincronización de GitHub permanece en el escritorio porque necesita el token de GitHub del propietario.
GET/api/projects/:id/eventsTransmisión SSE en vivo de historial, flujo de trabajo y actividad del asistente; El único canal push del teléfono.
OBTENER, PUBLICAR, PONER, BORRAR/api/notifications, /mark-all-read, /:idLeer, marcar como leído y eliminar notificaciones.
GET/api/ai/status, /models, /agentsAsistente de descubrimiento.
POST/api/ai/chat/stream, chat/abort, chat/queue, permission/reply, sessions/state, sessions/controlSesiones de asistente.

Debido a que la lista está fija en el sidecar, una función que necesita otra ruta (por ejemplo, carga de archivos o envío de GitHub) es una función solo de escritorio hasta que la lista cambia.

Lo que almacena el teléfono

ArtículoAlmacenamientoNotas
Origen(es) de la puerta de enlaceSecureStoreEl anfitrión preferido más los alternos desde el enlace de emparejamiento.
Ficha de dispositivotienda segura, WHEN_UNLOCKED_THIS_DEVICE_ONLYNunca abandona el dispositivo excepto como encabezado portador a la puerta de enlace.
Certificado de huella digitalSecureStoreComparado con el certificado de la puerta de enlace en cada conexión.
Cola sin conexión, marcadores de sesiónSecureStoreMensajes redactados sin conexión y el último estado de las sesiones vistas.

En una compilación de desarrollo de navegador, los mismos datos recurren al almacenamiento local, que no está cifrado. Úselo sólo con combinaciones desechables.

Pantallas

Archivo de rutaPantalla
app/index.tsxEntrada: sin emparejamiento → la pantalla de emparejamiento; emparejado → proyectos
app/connect.tsx, app/pair.tsxEmparejamiento: escanea el código QR con la cámara o pega el enlace
app/(app)/projects/index.tsxLista de proyectos
app/(app)/projects/[id].tsxun proyecto
app/(app)/projects/[id]/commit/[oid].tsxUn compromiso y sus cambios.
app/(app)/projects/[id]/pulls/[number].tsxUna solicitud de extracción: revisar y fusionar
app/(app)/assistant.tsxChat asistente
app/(app)/activity.tsxActividad en vivo
app/(app)/settings.tsxConfiguración de conexión y dispositivo

Las rutas utilizan las convenciones de archivos de Expo Router: (app) es un grupo que comparte un diseño sin agregar un segmento de URL, y [id] es un parámetro.

Cola de asistente sin conexión

Cuando no se puede acceder al escritorio, un mensaje escrito en el asistente se pone en cola en el teléfono en lugar de perderse:

ReglaValor
DóndeSecureStore, para que una aplicación eliminada mantenga la cola
lo que se almacenaprojectId, text, opcional sessionId, agent, mode (general, cad, cam, gcode, ruta de herramienta; general predeterminado) y queuedAt
Capacidad50 entradas; los más viejos son eliminados primero
cuando drenaCuando la aplicación vuelve al primer plano con un emparejamiento almacenado
CómoCada entrada abre un nuevo turno de transmisión y lee hasta done; un error evento o una transición en segundo plano lo mantiene en cola
ComentarioUn brindis: "Mensaje en cola enviado" o "N mensajes en cola enviados"

Sólo los errores de conectividad ponen en cola un mensaje. Un envío cuenta como fuera de línea cuando el cliente informa el estado 0 o el texto de error menciona una falla de la red, tiempo de espera, conexión rechazada o similar; Los errores HTTP y comerciales ("la solicitud a... falló con...") se muestran en lugar de estar en cola.

En 3D

El móvil y el sidecar Arrastrar para orbitar · desplazarse para hacer zoom · arrastrar con el botón derecho para desplazarse
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.