Перейти к содержанию
CADCAMFUN
Документы

Документация

Мобильный компаньон

Клиент iOS для сопряженного рабочего стола с закреплением сертификатов, проверкой проектов и сеансами общего помощника.

Автоматически переведено с английского. Смотреть оригинал на английском

Платформа и возможности

apps/mobile — это приложение Expo SDK 57, использующее React Native 0.86.3, React 19.2, Expo Router, NativeWind, Reanimated и Gesture Handler. Поддерживаемый закрепленный сетевой транспорт реализован в Swift локальным companion-net модуль. Идентификатор пакета iOS: com.cadcamfun.mobile.

Телефон считывает проекты, просматривает историю и запросы на включение, распределяет рабочие процессы, получает информацию об активности и взаимодействует с сеансами помощников, запущенными на сопряженном рабочем столе. Настольный компьютер продолжает владеть базой данных, вычислениями геометрии, учетными данными поставщика ИИ и выполнением рабочих процессов. Для этих операций необходим доступный работающий рабочий стол.

Используйте родную сборку iOS

Expo Go не включает companion-net и не может подключиться к сопряженному рабочему столу. Собственные запросы завершаются неудачей, когда модуль закрепления недоступен. Резервный вариант веб-разработки использует выборку браузера и локальное хранилище; он не обеспечивает встроенное закрепление сертификата.

Структура приложения

Expo Router отделяет экраны подключения от вкладок аутентифицированных приложений. app/connect.tsx обрабатывает ввод сопряжения, app/pair.tsx принимает глубокие ссылки и app/(app) содержит проекты, помощник, активность и настройки. Экраны проекта включают панели обзора/истории/вытягивания/рабочего процесса, сведения о фиксации и проверку запроса на включение.

  • components/: многоразовые элементы управления, панели проектов, расшифровка помощника и пользовательский интерфейс подключения.
  • lib/client.ts: типизированный клиент через внедрённый транспорт; Типы API импортируются без среды выполнения сервера.
  • lib/pairing.ts, native.ts, и storage.ts: проверка сопряжения, выбор транспорта и сохранение учетных данных.
  • lib/sse.ts, live-events.ts, и chat-log.ts: анализ потока, живые подписки и состояние расшифровки.
  • modules/companion-net/: Модуль Expo и реализация HTTPS, закрепленная Swift.

Объем транспорта и шлюза

Сопутствующий шлюз отделен от прослушивателя обратной связи боковой машины. По умолчанию он выключен. Включение этого параметра запускает HTTPS-сервер на 0.0.0.0, используя порт 8443, если не выбран другой допустимый порт. Служба сохраняет свое включенное состояние и возобновляет его после запуска сайдкара. Брандмауэр настольного компьютера и сетевой маршрут должны разрешать телефону доступ к этому прослушивателю.

Телефон отправляет отзывный токен устройства. Шлюз сохраняет свой хэш SHA-256, проверяет метод/путь запроса на соответствие списку разрешений и перенаправляет принятые запросы в API обратной связи с помощью токена рабочего стола. Телефон не получает этот токен запуска. Неверная аутентификация возвращает 401, запрещенные маршруты возвращают 403, повторная неудачная аутентификация может возвращать 429, а недоступный восходящий поток возвращает 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.

Доступ к устройству включает операции записи.

В настоящее время шлюз разрешает запросы на фиксацию, ветвление, извлечение и восстановление контроля версий, а также проверку и слияние запросов на включение. Токены устройств относятся к политике маршрутизации шлюза; они не являются ролью только для чтения или ограничением для каждого проекта. Отзовите потерянный или ненадежный телефон в настройках настольного помощника.

Шлюз ограничивает неудачные попытки аутентификации: после десяти неудачных попыток передачи данных с одного IP-адреса в течение 60 секунд последующие запросы с этого адреса получают HTTP 429 до истечения срока действия окна (apps/sidecar/src/services/companion-gateway.ts).

Сеансы Ассистента и офлайн-сообщения

Компаньон отправляет запросы в чат на POST /api/ai/chat/stream и анализирует события, отправленные сервером. Идентификатор сеанса позволяет продолжить разговор на рабочем столе. Клиент может управлять сообщениями или ставить их в очередь, прерывать ход, отвечать на вопросы и отвечать на запросы разрешений. Настройте поставщика модели на рабочем столе; перед использованием телефон запрашивает статус AI.

Если поток заканчивается без терминала done или error кадр и не был отменен, клиент сообщает о неполном соединении. Собственный транспорт закрывает дескриптор потока при отмене и завершении. Собственное декодирование сохраняет неполные скаляры UTF-8 между фрагментами байтов.

Сообщения Ассистента, которые невозможно отправить, могут попасть в постоянную очередь. Он сохраняет не более 50 записей, удаляя самые старые при заполнении и повторяет попытки восстановления в приоритетном режиме и подключения. Неудачные записи остаются в очереди. В этой очереди хранятся сообщения для последующего выполнения; это не автономная копия геометрии проекта или автономная среда выполнения ИИ.

Стройте и запускайте

Из корня репозитория
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

Команда сборки экспортирует пакет iOS JavaScript в apps/mobile/dist; он не производит IPA. Для команд запуска iOS требуются macOS, Xcode и CocoaPods. Для установки устройства также требуется доверенное устройство, режим разработчика и группа подписи Apple, настроенная для созданного проекта Xcode. native:generate запускает предварительную сборку Expo для iOS без установки модулей. Для повседневной работы, start (псевдоним dev) запускает пакет клиента разработки Expo, ios:dev запускает его на локальном хосте и открывает симулятор iOS, ios:build компилирует приложение отладки без запуска упаковщика и web запускает веб-цель Expo. test скрипт запускается bun test test внутри apps/mobile.

.github/workflows/ci.yml определяет сопутствующую проверку типов, логические тесты и экспорт JavaScript. .github/workflows/ios.yml генерирует проект Xcode, создает неподписанное приложение-симулятор выпуска, соединяет его с работающим дополнительным приложением, проверяет список проверенных проектов и делает снимок экрана. Эти настроенные проверки не подтверждают принятие физического устройства, подписи, TestFlight или реального поставщика.

Безопасность хранения и устройства

В родной iOS учетные данные для сопряжения хранятся в Expo SecureStore. В записи о сопряжении используется WHEN_UNLOCKED_THIS_DEVICE_ONLY. Записи автономной очереди и маркеры сеанса также используют SecureStore. Резервный вариант браузера использует локальное хранилище для разработки.

Приложение запрашивает биометрические возможности и использует expo-local-authentication для локальной аутентификации с включенным резервным кодом доступа к системе. Биометрический пользовательский интерфейс не меняет разрешения маршрутизации на стороне сервера шлюза. Отзыв устройства контролируется сопряженным рабочим столом.

Настольный компьютер хранит сертификат шлюза и закрытый ключ в сопутствующем каталоге данных приложения; ключ написан с разрешениями только владельца. Замена этого сертификата изменяет закрепленный отпечаток пальца и требует нового доверенного соединения.

Рабочий процесс проверки проекта

  1. Откройте «Проекты» и выберите проект рабочего стола.
  2. Проверьте его рабочее состояние, ветки, фиксации, запросы на включение или запуск рабочего процесса.
  3. Откройте коммит, чтобы просмотреть его различия, или откройте запрос на включение, чтобы просмотреть изменения и отправить вердикт.
  4. Используйте доступные действия слияния/закрытия или диспетчеризации рабочего процесса, если это необходимо для проекта.
  5. Откройте Assistant с выбранным контекстом проекта, чтобы продолжить или начать сеанс AI.

Все изменения выполняются на рабочем столе. Обрыв сети, отозванная авторизация или остановленный рабочий стол препятствуют работе нового сервера; Сообщения помощника, поставленные в локальную очередь, повторяются позже.

Клиентский интерфейс

CompanionClient принимает 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.

Ошибки JSON становятся CompanionError со статусом и сообщением. Потоковая передача чата и событий в реальном времени использует общий анализатор SSE, поэтому произвольные границы сетевых фрагментов не становятся границами событий приложения. Тесты внедряют транспорты без импорта собственных модулей или запуска симулятора.

Сопряжение телефона

  1. На рабочем столе откройте «Настройки» и сопутствующую панель для мобильных устройств или /settings/companionи включите шлюз.
  2. Создайте именованное сопряжение устройств и отобразите QR-код. Ссылка содержит кандидатов на хосты HTTPS, токен устройства и отпечаток сертификата.
  3. На iOS отсканируйте QR-код или вставьте cadcamfun://pair связь. Разрешите доступ к локальной сети при появлении соответствующего запроса.
  4. Приложение проверяет ссылку, соревнуется с объявленными кандидатами на хосты и сохраняет первое успешное работоспособное соединение.
  5. Убедитесь, что устройство отображается в настройках рабочего стола. Используйте действие отзыва рабочего стола, чтобы лишить его доступа.

Кандидаты на хост включают подходящие адреса частного IPv4 и оверлейной сети; шлюз объявляет не более шести обнаруженных адресов. Текущим прослушивателем является IPv4, поэтому обнаруженные адреса IPv6 не объявляются. VPN или оверлейная сеть уже должны обеспечивать маршрутизацию для использования вне локальной сети; сопряжение не создает ретранслятор или VPN.

Закрепление сертификата

Реализация Swift использует эфемерные URLSession экземпляры с делегатом доверия. Он принимает листовой сертификат только в том случае, если хэш SHA-256 его байтов DER равен отпечатку пальца от спаривания. Для запросов требуется HTTPS, перенаправления отклоняются, а собственные вызывающие программы никогда не переключаются на транспорт браузера автоматически.

Таким образом, доверие к сертификату исходит от ссылки сопряжения. Считайте QR-код и вставленную ссылку учетными данными. Ссылку с неожиданным источником или отпечатком следует заменять в процессе сопряжения рабочего стола, а не в обход проверки TLS.

Диагностика соединения

  • Нет родного транспорта: установите сборку разработки или выпуска iOS, содержащую локальный модуль.
  • Нет доступного хоста: проверьте разрешение локальной сети, брандмауэр рабочего стола, объявленный адрес, порт шлюза и сетевую маршрутизацию.
  • 401: токен устройства недействителен или отозван; создать новую пару.
  • 403: конечная точка находится за пределами списка разрешенных сопутствующих объявлений.
  • Несоответствие сертификата: снова выполните сопряжение с текущим сертификатом рабочего стола.
  • Помощник недоступен: проверьте конфигурацию поставщика настольных компьютеров и работает ли сайдкар.

Настройки телефона и местное состояние

ПараметрПо умолчаниюПоведение
ПоявлениеСистемаВыберите «Система», «Светлый» или «Темный». Система следует за iOS до тех пор, пока не будет переопределена.
ГаптикаВключеноГалочки выбора и обратная связь об успехе/ошибке имеют отдельные переключатели.
Блокировка идентификатора лицаНеполноценныйДля включения необходимы доступные зарегистрированные биометрические данные и успешная системная аутентификация.
Блокировка на фонеВключеноЕсли биометрическая блокировка включена, переход в неактивный/фоновый режим блокирует сопряженное приложение.
Подключение к рабочему столуТекущее сопряжениеПоказывает адрес и префикс отпечатка пальца; нажатие на строку рабочего стола перепроверяет подключение.
Сообщения в очередиНольПоказывает ожидающие сообщения помощника, пока рабочий стол недоступен.

Настройки пользовательского интерфейса хранятся в AsyncStorage в разделе cadcamfun.ui.v1; учетные данные для сопряжения, сообщения в очереди и маркеры просмотренных сеансов используют SecureStore. Магазин пользовательского интерфейса запоминает выбранный проект и последний сеанс каждого проекта для одного сопряженного рабочего стола. При изменении идентификатора рабочего стола запомненное сопоставление проекта/сеанса очищается, поэтому оно не используется повторно на несвязанном сервере.

Координатор блокировки пропускает экраны загрузки и подключения и отображает полноэкранное наложение разблокировки для сопряженного приложения. Он не приостанавливает сеансы на стороне сервера и не отзывает токен. При отключении сопряжения сохраненное сопряжение телефона удаляется и возвращается в Connect; отзыв рабочего стола — это отдельное действие, которое предотвращает повторную аутентификацию токена.

Пример администрирования шлюза

Эти запросы выполняются к API обратной связи рабочего стола с его токеном запуска, а не к телефонному шлюзу. Используйте изолированный экземпляр разработки. Замените пример порта портом из события готовности и укажите токен этого процесса.

Проверьте и включите шлюз разработки
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}'

Статусный ответ содержит enabled, значение, допускающее нулевое значение port, значение, допускающее нулевое значение fingerprint, предложенный host, и devices. Служба принимает явные порты от 1024 до 65535. Уже используемый порт не может запустить прослушиватель; выберите другой порт и заново создайте адрес сопряжения.

Создание именованного сопряжения устройств
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"}'

Замените пример хоста адресом, на который может маршрутизироваться телефон. При успешном создании пары возвращается HTTP 201 с устройством. id и удостоверение link. Обрезанное имя должно содержать символы 1–60. Отсканируйте/вставьте эту ссылку лично; не копируйте его в отчет об ошибке. Создание токена не приводит к автоматическому включению шлюза.

Чтобы удалить доступ, отправьте DELETE /api/companion/devices/<id> используя десктопную авторизацию. Чтобы остановить весь новый трафик шлюза, отправьте POST /api/companion/disable. Хэши устройств проверяются при каждом запросе, поэтому отозванные токены отклоняются при последующих запросах.

Восстановление без потери контекста

  1. Коснитесь строки подключения к рабочему столу в настройках, чтобы повторить проверку работоспособности рекламируемых хостов.
  2. Если произошел сбой только одного сетевого пути, проверьте правильный маршрут Wi-Fi/точки доступа/VPN и повторно сгенерируйте QR-код после изменения адреса рабочего стола.
  3. Если авторизация не удалась, отзовите устаревшее устройство на рабочем столе и создайте новое сопряжение.
  4. Если произошел сбой только в потоке помощника, повторно откройте сеанс проекта и проверьте его состояние перед повторной отправкой той же инструкции.
  5. Проверьте количество сообщений в очереди, прежде чем отправлять дубликат запроса; операции в очереди повторяются позже.

Автономная очередь имеет ограниченное хранение и воспроизводит каждую ожидающую операцию посредством нового запроса чата, содержащего сохраненный идентификатор сеанса, если он доступен. Это не гарантия единоразовой доставки. Отключение сети после выполнения сервера может привести к тому, что клиент не будет уверен в завершении; проверьте полученное состояние проекта/сеанса перед повторением изменения.

Якоря реализации: app/(app)/settings.tsx, components/layout/AppLockCoordinator.tsx, lib/store.ts, lib/server.tsx, и lib/offline-queue.ts.

Список разрешенных шлюзов

Телефон общается с настольным компьютером только через сопутствующий шлюз, который допускает этот фиксированный набор маршрутов и перенаправляет их в API обратной связи:

МетодыШаблон путиЦель
GET/api/healthПроверка доступности.
GET/api/projects, /api/projects/:idСписок проектов и заголовок.
ПОЛУЧИТЬ, ОТПРАВИТЬ/api/projects/:id/vcs/* (кроме remote, push, pull), /pulls/*, /actions/*История, запросы на включение, обзоры и рабочие процессы. Синхронизация GitHub остается на рабочем столе, поскольку для нее требуется токен GitHub владельца.
GET/api/projects/:id/eventsПрямая трансляция SSE истории, рабочего процесса и активности помощников; единственный push-канал телефона.
ПОЛУЧИТЬ, ОТПРАВИТЬ, ПОСТАВИТЬ, УДАЛИТЬ/api/notifications, /mark-all-read, /:idЧитайте, отмечайте прочитанными и удаляйте уведомления.
GET/api/ai/status, /models, /agentsПомощник открытия.
POST/api/ai/chat/stream, chat/abort, chat/queue, permission/reply, sessions/state, sessions/controlАссистентские сеансы.

Поскольку список фиксирован в боковой панели, функция, для которой требуется другой маршрут (например, загрузка файла или отправка GitHub), является функцией только для настольных компьютеров, пока список не изменится.

Что хранит телефон

ЭлементХранилищеПримечания
Источник(и) шлюзаSecureStoreПредпочитаемый хост плюс альтернативы из ссылки для сопряжения.
Токен устройстваSecureStore, WHEN_UNLOCKED_THIS_DEVICE_ONLYНикогда не покидает устройство, кроме как в виде заголовка носителя к шлюзу.
Отпечаток сертификатаSecureStoreПо сравнению с сертификатом шлюза при каждом соединении.
Офлайн-очередь, маркеры сеансаSecureStoreСообщения, созданные в автономном режиме, и последнее состояние сеансов.

В сборке для разработки браузера те же данные возвращаются в локальное хранилище, которое не зашифровано. Используйте его только с одноразовыми парами.

Экраны

Файл маршрутаЭкран
app/index.tsxВвод: нет сопряжения → экран сопряжения; парные → проекты
app/connect.tsx, app/pair.tsxСопряжение: отсканируйте QR-код камерой или вставьте ссылку.
app/(app)/projects/index.tsxСписок проектов
app/(app)/projects/[id].tsxОдин проект
app/(app)/projects/[id]/commit/[oid].tsxКоммит и его изменения
app/(app)/projects/[id]/pulls/[number].tsxЗапрос на включение: просмотр и объединение
app/(app)/assistant.tsxАссистентский чат
app/(app)/activity.tsxЖивая деятельность
app/(app)/settings.tsxПодключение и настройки устройства

Маршруты используют соглашения о файлах Expo Router: (app) это группа, которая использует общий макет без добавления сегмента URL-адреса, и [id] является параметром.

Очередь автономного помощника

Если рабочий стол недоступен, сообщение, набранное в помощнике, вместо потери будет поставлено в очередь на телефоне:

ПравилоЦенить
ГдеSecureStore, поэтому убитое приложение сохраняет очередь
Что хранитсяprojectId, text, необязательный sessionId, agent, mode (общее, CAD, кулачок, gcode, траектория инструмента; общее по умолчанию) и queuedAt
Емкость50 записей; самые старые отбрасываются первыми
Когда он истощаетКогда приложение возвращается на передний план с сохраненным сопряжением
КакКаждая запись открывает новую очередь потоковой передачи и читается до тех пор, пока done; а error событие или фоновый переход помещают его в очередь
Обратная связьТост: «Сообщение в очереди отправлено» или «Отправлено N сообщений в очереди».

Только сбои подключения помещают сообщение в очередь. Отправка считается автономной, если клиент сообщает о состоянии 0 или в тексте ошибки упоминается сбой сети, тайм-аут, отказ в соединении или что-то подобное; HTTP и бизнес-ошибки («запрос… не выполнен с…») отображаются вместо постановки в очередь.

Через 3Д

Мобиль и сайдкар Перетащите на орбиту · прокрутите, чтобы увеличить · перетащите вправо, чтобы панорамировать
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.