Документация
Мобильный компаньон
Клиент 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 для локальной аутентификации с включенным резервным кодом доступа к системе. Биометрический пользовательский интерфейс не меняет разрешения маршрутизации на стороне сервера шлюза. Отзыв устройства контролируется сопряженным рабочим столом.
Настольный компьютер хранит сертификат шлюза и закрытый ключ в сопутствующем каталоге данных приложения; ключ написан с разрешениями только владельца. Замена этого сертификата изменяет закрепленный отпечаток пальца и требует нового доверенного соединения.
Рабочий процесс проверки проекта
- Откройте «Проекты» и выберите проект рабочего стола.
- Проверьте его рабочее состояние, ветки, фиксации, запросы на включение или запуск рабочего процесса.
- Откройте коммит, чтобы просмотреть его различия, или откройте запрос на включение, чтобы просмотреть изменения и отправить вердикт.
- Используйте доступные действия слияния/закрытия или диспетчеризации рабочего процесса, если это необходимо для проекта.
- Откройте 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, поэтому произвольные границы сетевых фрагментов не становятся границами событий приложения. Тесты внедряют транспорты без импорта собственных модулей или запуска симулятора.
Сопряжение телефона
- На рабочем столе откройте «Настройки» и сопутствующую панель для мобильных устройств или
/settings/companionи включите шлюз. - Создайте именованное сопряжение устройств и отобразите QR-код. Ссылка содержит кандидатов на хосты HTTPS, токен устройства и отпечаток сертификата.
- На iOS отсканируйте QR-код или вставьте
cadcamfun://pairсвязь. Разрешите доступ к локальной сети при появлении соответствующего запроса. - Приложение проверяет ссылку, соревнуется с объявленными кандидатами на хосты и сохраняет первое успешное работоспособное соединение.
- Убедитесь, что устройство отображается в настройках рабочего стола. Используйте действие отзыва рабочего стола, чтобы лишить его доступа.
Кандидаты на хост включают подходящие адреса частного 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. Хэши устройств проверяются при каждом запросе, поэтому отозванные токены отклоняются при последующих запросах.
Восстановление без потери контекста
- Коснитесь строки подключения к рабочему столу в настройках, чтобы повторить проверку работоспособности рекламируемых хостов.
- Если произошел сбой только одного сетевого пути, проверьте правильный маршрут Wi-Fi/точки доступа/VPN и повторно сгенерируйте QR-код после изменения адреса рабочего стола.
- Если авторизация не удалась, отзовите устаревшее устройство на рабочем столе и создайте новое сопряжение.
- Если произошел сбой только в потоке помощника, повторно откройте сеанс проекта и проверьте его состояние перед повторной отправкой той же инструкции.
- Проверьте количество сообщений в очереди, прежде чем отправлять дубликат запроса; операции в очереди повторяются позже.
Автономная очередь имеет ограниченное хранение и воспроизводит каждую ожидающую операцию посредством нового запроса чата, содержащего сохраненный идентификатор сеанса, если он доступен. Это не гарантия единоразовой доставки. Отключение сети после выполнения сервера может привести к тому, что клиент не будет уверен в завершении; проверьте полученное состояние проекта/сеанса перед повторением изменения.
Якоря реализации: 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 и бизнес-ошибки («запрос… не выполнен с…») отображаются вместо постановки в очередь.