DSH iOS

DSH iOS Simulator

Живой интерактивный симулятор iOS внутри диалога DeepSeek Harness — плюс ваш настоящий iPhone по USB.
22 инструмент агента • живая MJPEG-панель в боковой панели • симулятор & реальный iPhone по USB • действия со строками списков/лент • горячая перезагрузка превью SwiftUI

npm: @zseven-w/dsh-ios · Текущий релиз плагина: 0.1.0-rc.3 · Проверено с DSH 0.1.1-rc.1

English · 简体中文 · 繁體中文 · 日本語 · 한국어 · Français · Español · Deutsch · Português · Русский · हिन्दी · Türkçe · ไทย · Tiếng Việt · Bahasa Indonesia

npm: @zseven-w/dsh-ios · Текущая версия плагина: 0.1.0-rc.3 · Проверено с DSH 0.1.1-rc.1


DSH iOS Simulator — a real iPhone inside the conversation

Реальный iPhone под управлением прямо из диалога DSH — вызовы инструментов слева, живая панель устройства справа

## Зачем нужен DSH iOS Simulator DSH iOS Simulator даёт агенту настоящий симулятор iOS прямо в диалоге — а вам отдаёт пиксели. Агент может загрузить устройство, собрать и запустить проект Xcode или Swift-пакет, управлять интерфейсом по идентификатору доступности или по тексту OCR, читать единый журнал и проверять процессы, бэктрейсы и утечки, пока живой поток устройства отображается в постоянной боковой панели, где можно нажимать, перетаскивать, поворачивать и нажимать Home прямо на видео. Те же команды работают и на реальном iPhone, подключённом по USB: плагин собирает и запускает WebDriverAgent на телефоне, туннелирует его порты управления и экрана через loopback и транслирует устройство в ту же панель, карточки и инструменты. Никаких блоков изображений и файлов записи экрана: визуальные байты попадают в интерфейс только через подписанные URL с ограниченным сроком действия, которые выдаёт веб-сервер DSH. | | | | --- | --- | | 🖥️ **Живой симулятор в диалоге** | MJPEG-поток serve-sim загруженного устройства, проксируемый через подписанные маршруты `/_dsh/dsh-ios/*` в постоянную правую панель — браузер никогда не обращается к порту serve-sim. | | 📱 **Реальный iPhone по USB** | `ios_real_start_wda` собирает и запускает WebDriverAgent на подключённом телефоне и туннелирует его порты управления (REST) и экрана (MJPEG) через loopback; дальше телефоном управляют те же панель, инструменты, карточки и статусная капсула. Устройство должно быть разблокировано, а каждое нажатие на реальном аккаунте ограничено правилами плагина «сначала идентифицируй, потом нажимай». | | 🛠️ **22 инструмент агента** | Устройства, загрузка/выключение, скриншот, взаимодействие, сборка и запуск, единый журнал, дерево UI на базе AXe и нажатие по элементу, действия со строками списков/лент, поиск/нажатие текста через Vision OCR, горячая перезагрузка превью SwiftUI, процессы, бэктрейс, утечки, информация о приложениях. | | 👆 **Интерактивная панель** | Нажимайте и перетаскивайте на живом видео; панель иконок Home / поворот / скриншот / обновление с подсказками при наведении; режимы размера (适应 · 50–125% · S/M/L); стили рамки (无框 / 边框 / 真机框); изменение ширины перетаскиванием до 960 px со сбросом двойным кликом; автоматическое расширение в альбомной ориентации. | | 🧾 **Строки списков и лент** | `ios_sim_ui_rows` превращает глубокие снимки доступности в пронумерованные строки с метками и универсально разобранными счётчиками; `ios_sim_tap_row` нажимает внутри строки по относительным координатам и проверяет действие по ожидаемому изменению счётчика на ±1 — единственное надёжное подтверждение, которое даёт приложение-список. | | 🔐 **Транспорт только через loopback** | serve-sim привязывается к 127.0.0.1 в выделенном диапазоне портов; каждый маршрут требует loopback-пира, loopback-`Host` и проверок Fetch-Metadata/Origin; HMAC-возможности истекают в течение 10 минут.. | | ⚡ **Горячая перезагрузка превью SwiftUI** | `ios_sim_preview` генерирует одноразовое хост-приложение вне вашего пакета, собирает ваши превью как dylib и горячо подменяет правки в запущенном симуляторе без перезапуска (~2–5 с). | | 🧭 **Семантическая автоматизация UI** | `ios_sim_ui_tree` выгружает дерево доступности (на базе AXe), а `ios_sim_tap_element` нажимает по метке или идентификатору; `ios_sim_find_text` делает OCR экрана, когда дерево пустое или вырожденное, а `ios_sim_tap_text` нажимает найденный текст — нажатия по идентичности и по тексту вместо угаданных координат. | ## Инструменты Все 22 инструмент регистрируются на любом хосте и возвращают только чистый JSON — визуальные байты попадают в интерфейс только через `presentationMeta` + подписанные маршруты, никогда в виде блоков изображений. udid симуляторов идут через simctl/serve-sim; udid физических устройств автоматически идут через WebDriverAgent. На хостах не-macOS (или когда serve-sim недоступен) инструменты остаются зарегистрированными, но вызовы завершаются понятной ошибкой; единственное исключение — `status` у `ios_sim_preview`, который честно сообщает `{ running: false }` на любом хосте. ### Основные инструменты симулятора | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_devices` | Перечисляет устройства симулятора iOS, доступные на этом Mac (udid, имя, среда выполнения, состояние) и какие из них загружены, плюс подключённые по USB физические iPhone в `realDevices` (udid, имя, osVersion, model, state, developerMode). Используйте его, чтобы узнать udid или имя для передачи другим инструментам. | — | | `ios_sim_boot` | Загружает устройство и запускает его живой поток serve-sim; поток остаётся жив во время диалога, чтобы панель показывала симулятор в реальном времени. | `udid` (обязателен — udid или имя устройства) | | `ios_sim_shutdown` | Выключает устройство; останавливает поток, если он нацелен на это устройство. | `udid` (обязателен) | | `ios_sim_screenshot` | Снимает PNG и возвращает краткую JSON-сводку (путь, байты, размеры, устройство); изображение отображается в карточке/панели, никогда как блок изображения. Работает на транслируемом симуляторе и на телефоне, подключённом по USB, через WebDriverAgent. | `udid` (необязателен — транслируемое устройство, иначе первый загруженный симулятор) | | `ios_sim_interact` | Взаимодействует с транслируемым устройством — симулятором или телефоном по USB: нажатие по нормализованным координатам 0..1, ввод текста (клавиатура США на симуляторе), нажатие аппаратной кнопки (`home`, `lock`, `volumeUp`…), прокрутка или отправка сенсорного жеста; когда действие устаканится (~300 мс), свежий скриншот показывает результат. | `action` (обязателен — `tap`/`type`/`button`/`gesture`/`scroll`), `x`/`y`, `text`, `name`, `json` | | `ios_sim_list_apps` | Перечисляет приложения, УСТАНОВЛЕННЫЕ на загруженном симуляторе или подключённом телефоне (bundle id, отображаемое имя, версия, признак системного) — bundle id стороннего приложения нельзя угадать, поэтому сначала выведите список или передайте `name` в `ios_sim_launch_app`. НЕУДАЧНОЕ перечисление бросает ошибку (например «устройство недоступно через CoreDevice») вместо пустого списка, поэтому `count: 0` всегда означает, что на устройстве действительно нет подходящего приложения. | `udid` (необязателен), `query` (подстрока без учёта регистра по отображаемому имени И bundle id, включая CJK), `include_system` (по умолчанию false) | | `ios_sim_launch_app` | Запускает установленное приложение на загруженном симуляторе или подключённом телефоне — по `bundleId` или по `name` (подстрока отображаемого имени без учёта регистра, разрешаемая через то же перечисление, включая CJK). Ровно одно из двух; при неудачном запуске или неоднозначном имени в ответе говорится, что делать дальше (`ios_sim_build_run` — для сборки из исходников). | `bundleId` или `name` (ровно одно), `udid`, `relaunch` | | `ios_sim_build_run` | Собирает `.xcodeproj`, `.xcworkspace` или Swift-пакет для симулятора, устанавливает собранный `.app` и запускает его; передайте udid физического устройства, чтобы вместо этого собрать, установить и запустить на телефоне (требуется подпись Apple Development). При неудаче результат содержит отфильтрованный хвост ошибок `xcodebuild`. Полная сборка занимает минуты. | `projectPath` (обязателен), `scheme`, `udid` (транслируемое → загруженное → iPhone самой новой среды выполнения, который загружается), `configuration` (по умолчанию `Debug`) | | `ios_real_start_wda` | Запускает WebDriverAgent (WDA) на подключённом по USB физическом iPhone — только реальные устройства, никогда симулятор. Подхватывает уже работающий WDA, если тот отвечает; иначе выполняет сборку/запуск `xcodebuild` (холодная сборка занимает минуты), затем ждёт готовности WDA и возвращает порты управления/MJPEG, которые использует живая панель. Запускайте первым, когда `ios_sim_screenshot` / `ios_sim_interact` / `ios_sim_ui_tree` / `ios_sim_tap_element` сообщают, что WDA не запущен для устройства. | `udid` (обязателен — udid физического устройства из `ios_sim_devices.realDevices`) | ### Инструменты дерева UI (на базе AXe) | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_ui_tree` | Выгружает дерево элементов доступности активного приложения (метки, идентификаторы, значения, фреймы в точках устройства) плюс размер экрана в точках — AXe на симуляторе, WebDriverAgent на телефоне по USB (там глубина по умолчанию ограничена: неограниченный снимок занятого приложения занимает ~32 с / 751 КБ, ограниченный ~2 с); вывод ограничен ~40 КБ (самые глубокие уровни обрезаются, ставится `truncated` + подсказка). | `udid` (необязателен), `max_depth`, `filter` (подстрока без учёта регистра по метке/идентификатору/типу) | | `ios_sim_tap_element` | Нажимает элемент по идентичности — сначала точное совпадение, затем подстрока без учёта регистра по `identifier`/`label`; вложенные дубликаты схлопываются в одну цель, неоднозначные совпадения перечисляют всех кандидатов. Нажатие попадает в центр элемента (AXe HID на симуляторе, WebDriverAgent на телефоне), затем скриншот через ~300 мс показывает эффект; передайте `expect_text` / `expect_gone`, и нажатие вместе с проверкой станут одним циклом запроса (`expected.matched`). | `udid` (необязателен), `identifier`, `label`, `expect_text`, `expect_gone` | ### Строки списков & лент Приложения-списки/ленты объединяют каждый элемент в одну ячейку доступности, метка которой несёт весь сводный текст и все счётчики («57 回复。18 喜欢。592 次查看») — отдельных дочерних кнопок для сопоставления нет, а ячейки строк появляются только на глубоком снимке. Эти два инструмента показывают такую структуру как строки и действуют внутри строки. | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_ui_rows` | Читает видимые строки списка/ленты активного приложения как строки, а не сырое дерево: каждая строка сообщает индекс, фрейм в точках, объединённую метку и счётчики, разобранные из этой метки (число + токен-классификатор, например `57 回复` → 回复=57, на китайском или английском — никакой словарь приложений не зашит). Строки появляются только на глубоком снимке: на телефоне `max_depth` по умолчанию равен 60, что стоит ~15–25 с / ~0.5 МБ за вызов (WDA обрабатывает запросы последовательно) — сначала используйте дешёвых наблюдателей (`ios_sim_find_text` / `ios_sim_ui_tree`). Счётчики разбираются эвристически, а ключи проходят цикл туда-обратно: передавайте ключ в `ios_sim_tap_row.expect_count` ровно так, как он указан в списке. Если строки не найдены, результат объясняет почему (недостаточная глубина / это не экран списка / действительно нет информации о доступности после глубокого чтения) — поверхностное чтение никогда не выдаётся за «у приложения нет информации о доступности»; строки за пределами экрана исключаются и считаются как `omittedOffscreen`. | `udid` (необязателен), `max_depth` (только телефон; по умолчанию 60) | | `ios_sim_tap_row` | Нажимает по относительной позиции внутри одной видимой строки списка (строку сообщает `ios_sim_ui_rows`: индекс с 0; x/y как доли фрейма этой строки — 0 = левый/верхний край, 1 = правый/нижний, по умолчанию 0.5 = центр) на симуляторе (AXe) или телефоне по USB (WebDriverAgent). Фрейм строки берётся из СВЕЖЕГО чтения дерева, поэтому абсолютные координаты экрана не угадываются; индекс вне диапазона ЗАВЕРШАЕТСЯ ошибкой (никогда не обрезается). Предохранитель: с `expect_count={key,delta}` инструмент проверяет действие, перечитывая метку строки и убеждаясь, что счётчик сдвинулся ровно на +1/−1 (`countCheck.verified`); если ключа нет среди разобранных счётчиков строки, нажатие ОТКЛОНЯЕТСЯ до его выполнения — нажатие на реальном устройстве никогда не является пробой. Без `expect_count` нажатие всё равно выполняется (явная позиция относительно строки И ЕСТЬ идентификация), но ничего не проверяется. | `udid` (необязателен), `index` (обязателен), `x`, `y` (доли 0..1), `max_depth`, `expect_count` (`{key, delta}`) | ### Инструменты OCR (Vision) | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_find_text` | Делает OCR ТЕКУЩЕГО экрана загруженного симулятора или телефона по USB с помощью собранного плагином помощника Vision (точное распознавание, zh-Hans + en-US, при первом использовании компилируется `swiftc` в `~/Library/Caches/dsh-ios/bin/ocr`). Используйте, когда дерево доступности пустое или вырожденное, для текста, отрисованного графикой (цифры бейджей, цены, вшитые в изображения), или чтобы независимо проверить, что на экране. Делает свежий скриншот и возвращает `{device, size, items:[{text, confidence, rect}]}` — rect это рамки в точках устройства (начало координат слева сверху), отсортированные по уверенности, вывод ограничен ~40 КБ (`truncated` отбрасывает хвост с наименьшей уверенностью; сузьте через `query` или поднимите `min_confidence`). | `udid` (необязателен), `query` (подстрока без учёта регистра), `min_confidence` (по умолчанию 0.3) | | `ios_sim_tap_text` | Делает OCR ТЕКУЩЕГО экрана и нажимает центр лучшего совпадения текста — те же правила «точное → содержит без учёта регистра → список кандидатов при неоднозначности», что и у `ios_sim_tap_element`, для текста, который дерево доступности не видит (приложения без a11y, цифры бейджей, текст, вшитый в изображения). На телефоне нажатие попадает в абсолютные точки устройства через WebDriverAgent; на транслируемом симуляторе отправляется нормализованным через управление serve-sim (сначала выполните `ios_sim_boot`). Через ~300 мс свежий скриншот показывает эффект; передайте `expect_text` / `expect_gone`, и нажатие вместе с проверкой станут одним циклом запроса (`expected.matched`). На РЕАЛЬНОМ устройстве каждое нажатие имеет реальные последствия — никогда не нажимайте неопознанный элемент управления, чтобы выяснить, что он делает. | `udid` (необязателен), `query` (обязателен), `min_confidence`, `expect_text`, `expect_gone` | | `ios_sim_wait_for` | Ждёт, пока текст появится или исчезнет с экрана, опрашивая тот же конвейер снимок+OCR, что и `ios_sim_find_text`, пока условие не выполнится или не истечёт тайм-аут (по умолчанию 8 с, максимум 60 с). Тайм-аут — это нормальный ответ `matched:false`, никогда не ошибка: один вызов вместо ручного цикла find_text (~1,2 с за круг на реальном iPhone). При совпадении `item` содержит текст OCR, уверенность и прямоугольник в точках устройства. | `udid` (необязательно), `text` (обязательно), `mode` (`appear`/`disappear`), `timeout_ms`, `min_confidence` | ### Инструмент журналов | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_logs` | Читает, что печатает приложение симулятора, из единого журнала устройства: `snapshot` (`log show --last `, по умолчанию 2m) или `follow` (ограниченный живой захват на `duration_seconds`, по умолчанию 10, максимум 60 — никогда не висящий поток). Вывод ограничен ~300 строками / 30 КБ с подсказкой по сужению. | `udid` (необязателен), `mode` (`snapshot`/`follow`), `duration`, `duration_seconds`, `bundle_id`, `predicate` (сырой NSPredicate, перекрывает `bundle_id`), `level` (`default`/`info`/`debug`), `grep` | ### Инструмент превью | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_preview` | Горячая перезагрузка превью SwiftUI, вживую в симуляторе: `start` (по умолчанию) проверяет пакет, генерирует одноразовое хост-приложение в кэше плагина (никогда внутри вашего пакета), собирает пакет как dylib для симулятора, устанавливает и запускает хост и следит за исходниками — каждая правка пересобирается и горячо подменяется без перезапуска (~2–5 с). Ошибки компиляции сохраняют последнее удачное превью и всплывают через `status`; одновременно работает одна сессия. | `packagePath` (обязателен для `start`), `udid`, `action` (`start`/`status`/`stop`), `previewFilter` (подстрока без учёта регистра по именам превью) | ### Инструменты отладки | Инструмент | Что делает | Ключевые параметры | | --- | --- | --- | | `ios_sim_processes` | Перечисляет работающие процессы приложений одного симулятора из его собственного launchd (видимый хосту pid, имя, bundle id) — источник pid для бэктрейса/утечек; udid физического устройства вместо этого перечисляет процессы телефона через devicectl. | `udid` (необязателен), `filter` (подстрока без учёта регистра по имени/bundle id) | | `ios_sim_backtrace` | Однократный пакетный LLDB (присоединение → бэктрейс потоков → отсоединение, никогда не интерактивный); вывод ограничен ~200 строками, главный поток первым, цель всегда проверяется как возобновлённая. Когда macOS запрещает присоединение (режим разработчика выключен), деградирует до движка `sample` из Xcode (без приостановки) и сообщает подсказку по включению. Только симуляторы — физические устройства отклоняются с указанием причины. | `udid` (необязателен), `pid` / `bundle_id`, `all_threads` (по умолчанию true) | | `ios_sim_leaks` | Анализирует утечки инструментом `leaks` из Xcode: `summary` (число утечек, всего утёкших байтов, топ ~30 типов) или `memgraph` (артефакт `.memgraph` для открытия в Xcode Instruments, здесь никогда не разбирается). Приложение приостанавливается на время сканирования и всегда возобновляется. Только симуляторы. | `udid` (необязателен), `pid` / `bundle_id`, `mode` (`summary`/`memgraph`) | | `ios_sim_app_info` | Факты об установленном приложении: путь к бандлу приложения, записываемый контейнер данных и значения Info.plist — через `simctl appinfo` (с запасным `get_app_container`) на симуляторе, через `devicectl` на телефоне по USB; `installed: false` плюс `note` с указанием `ios_sim_list_apps` для отсутствующих приложений. | `udid` (необязателен), `bundle_id` (обязателен) | ## Поверхности отображения - **Боковая панель — «iOS 模拟器».** Живой вид живёт в постоянной правой панели (фиксированный док, отодвигающий диалог, или центрированный оверлей на узких вьюпортах). Она отображает живой MJPEG-поток и принимает клик-для-нажатия и перетаскивание-для-жестов прямо на видео, с панелью иконок (Home, скриншот, поворот, обновление), кнопки которой имеют подсказки при наведении. Управление размером предлагает **适应** (по ширине панели), масштаб **50–125%** логической ширины устройства и пресеты **S / M / L**, задающие короткую сторону устройства (ширина в портрете; в альбомной ориентации масштабируется так, чтобы устройство сохраняло физический размер). Стили рамки — **无框 / 边框 / 真机框** (без рамки / ободок / реалистичный корпус устройства) с пропорциональным радиусом скругления. Когда устройство поворачивается в альбомную ориентацию, панель автоматически расширяется до удобного размера и возвращает вашу ширину при повороте обратно — ручное перетаскивание за это время всегда выигрывает. Ручка на левом краю тянет панель шире/уже (макс. 960 px; двойной клик сбрасывает на ширину по умолчанию). Когда цель потока — подключённый по USB iPhone, та же панель показывает MJPEG-поток WebDriverAgent телефона с теми же элементами управления. - **Компактные карточки диалога.** Результаты инструментов отображаются как однострочные карточки без встроенных изображений: единый заголовок **«iOS 模拟器»**, подпись действия (Загрузка / Скриншот / Взаимодействие / Сборка и запуск / Запуск WebDriverAgent), имя устройства, бейдж статуса и подсказка «открыть в боковой панели». Клик по строке открывает панель; клики по кнопкам, ссылкам или самому живому кадру её не вызывают. - **Статусная капсула над полем ввода.** Пока панель закрыта и поток онлайн, над полем ввода появляется маленькая капсула с зелёной точкой (`` · 实时), открывающая панель по клику. Она привязана к сессии: отображается и опрашивается только пока в текущем диалоге смонтированы результаты симулятора, и останавливается при переключении на сессию без них. - **Стандартный режим и режим Code.** Стандартные сессии используют спроецированный хостом `presentationMeta`. Вложенные диспетчи Code Mode (PTC) никогда не несут meta, поэтому клиент восстанавливает идентичную meta из сохраняемого JSON результата — панель, карточки и капсула работают в обоих режимах. ## Безопасность - Браузер никогда не обращается к порту serve-sim. Каждый байт проходит через источник веб-сервера DSH по принадлежащим плагину маршрутам `/_dsh/dsh-ios/*`: `/stream/` (MJPEG-прокси), `/screenshot/` (кэшированный PNG), `/ws?token=…` (ретрансляция HID-управления), плюс эндпоинты `/grant`, `/capture` и `/status`. - Токены — это HMAC-SHA256-возможности (`base64url(payload).base64url(mac)`), истекающие в течение 10 минут и подписанные ключом на каждый домашний каталог DSH (`/cache/dsh-ios/stream-access.key`, 0600, создаётся атомарно). - Каждый маршрут применяет ограждение loopback/доверенного транспорта до проверки любой возможности: адрес loopback-пира, loopback-`Host` (DNS-ребиндинг отклоняется) и проверки Fetch-Metadata/Origin. Маршрут скриншотов отдаёт только файлы внутри каталога кэша плагина (символические ссылки отклоняются, проверка вхождения через `realpath`). - serve-sim работает как дочерний процесс на переднем плане только на loopback, в выделенном диапазоне портов (3181–3244), так что собственный serve-sim пользователя на порту 3100 никогда не затрагивается; `--host` не используется.. - **Усыновление/возврат осиротевших** — если предыдущий хост DSH был убит нештатно и его помощник serve-sim выжил, то же устройство усыновляется (рукопожатие сироты считается авторитетным); устаревший помощник, занимающий слот под другое устройство, возвращается через `serve-sim -k` и перезапускается один раз. - **Keep-alive + остановка при простое** — упавший поток перезапускается в фоне (~5 с задержки); при нуле потребителей поток автоматически останавливается через 5 минут. Намеренные остановки никогда не оспариваются. (Раннер реального устройства намеренно исключён из сбора по простою: его перезапуск стоит многоминутной пересборки `xcodebuild`.) ## Требования - **macOS с полным Xcode** — не только Command Line Tools. `xcodebuild`, `xcrun simctl` и среды выполнения симулятора поставляются с Xcode. - **Хотя бы одна среда выполнения симулятора iOS**, установленная в Xcode. - **DSH ≥ 0.1.0-rc.6 с веб-бандлом** для панели. Headless-профили тоже работают: все 22 инструмент функционируют нормально, просто без живого вида. - **Хосты не-macOS**: плагин загружается и все 22 инструмент регистрируются, но каждый вызов возвращает понятную ошибку (`iOS Simulator requires macOS with Xcode …`). - **serve-sim** поставляется как npm-зависимость этого плагина, поэтому на реальных установках разрешается локально; запасной вариант `npx -y serve-sim` покрывает деревья разработки (первое использование требует сети). - **AXe** (необязательно — нужен только инструментам на базе AXe: `ios_sim_ui_tree` / `ios_sim_tap_element`, плюс `ios_sim_ui_rows` / `ios_sim_tap_row` на симуляторе): `brew install cameroncooke/axe/axe`, или позвольте плагину автоматически скачать зафиксированный релиз (v1.8.0, с проверкой SHA-256) в `~/Library/Caches/dsh-ios/bin`. `DSH_IOS_AXE_BIN` переопределяет разрешение; `DSH_IOS_AXE_OFFLINE=1` отключает загрузку. - **Vision OCR** (необязательно — нужен только `ios_sim_find_text` / `ios_sim_tap_text`): плагин при первом использовании компилирует встроенный `assets/ocr.swift` с помощью `swiftc` в `~/Library/Caches/dsh-ios/bin/ocr` (распознавание zh-Hans + en-US). - **Присоединение lldb требует режима разработчика macOS**: выполните один раз `sudo DevToolsSecurity -enable`. До этого `ios_sim_backtrace` использует движок `sample` из Xcode (без приостановки), а `ios_sim_leaks` деградирует с подсказкой по включению.. Первая сборка WDA устанавливает подписанный WebDriverAgentRunner: доверьте его сертификату на устройстве по запросу и повторно выполните `ios_real_start_wda`, когда истечёт подписной профиль бесплатной команды (срок 7 дней). ## Установка в DSH ```sh dsh plugin --profile web add @zseven-w/dsh-ios@latest dsh web ``` ## Быстрый старт Типичный первый диалог: 1. **Найдите устройства** — «Перечисли доступные симуляторы.» → `ios_sim_devices`. 2. **Загрузите** — «Загрузи iPhone 17 Pro.» → `ios_sim_boot`. Поток запускается, и **панель «iOS 模拟器»** открывается: устройство вживую в боковой панели. (Кликните по любой строке карточки симулятора или по статусной капсуле над полем ввода, чтобы открыть её снова.) 3. **Нажмите на видео** — нажимайте или перетаскивайте прямо на панели; или позвольте агенту управлять UI: «Открой Настройки, затем нажми General.» → `ios_sim_interact` (или `ios_sim_ui_tree` + `ios_sim_tap_element` для нажатий по идентичности; `ios_sim_find_text` + `ios_sim_tap_text` для нажатий по тексту; `ios_sim_ui_rows` + `ios_sim_tap_row` для приложений-списков/лент). 4. **Соберите и запустите ваше приложение** — «Собери и запусти /path/to/MyApp.xcodeproj.» → `ios_sim_build_run`. Полная сборка занимает минуты; когда она завершится, приложение запустится на симуляторе, и вы увидите его вживую в панели. 5. **Горячая перезагрузка превью** — «Покажи превью SwiftUI пакета /path/to/MyPackage.» → `ios_sim_preview start`. Отредактируйте файл исходников, и превью горячо подменится в запущенном симуляторе за ~2–5 с — без перезапуска. 6. **Управляйте реальным iPhone** — подключите телефон по USB (кабель с данными), разблокируйте его и скажите «Запусти WebDriverAgent на телефоне.» → `ios_real_start_wda`. Панель переключится на живой поток телефона, и каждый инструмент примет его udid из `realDevices`; при неудачном вызове прочитайте закодированную причину в статусе панели (`device-locked`, `cert-untrusted`, `profile-expired`, `tunnel-failed`, `device-unplugged`). ## Устранение неполадок - **Бэктрейс использует `sample` вместо lldb, или leaks жалуется на ограниченную проверку** — режим разработчика macOS выключен. Выполните один раз `sudo DevToolsSecurity -enable` и повторите. До этого инструменты аккуратно деградируют: `ios_sim_backtrace` переключается на `sample` из Xcode (символизированный, без приостановки), а `ios_sim_leaks` сообщает подсказку по включению. - **`ios_sim_ui_tree` / `ios_sim_tap_element` нужен AXe** — установите через `brew install cameroncooke/axe/axe` или позвольте плагину скачать зафиксированный релиз при первом использовании (нужна сеть до github.com). Сообщение об ошибке всегда содержит полную подсказку по установке; `DSH_IOS_AXE_BIN=/path/to/axe` переопределяет разрешение. Инструментам строк (`ios_sim_ui_rows` / `ios_sim_tap_row`) AXe тоже нужен на симуляторе. - **`ios_sim_find_text` / `ios_sim_tap_text` сообщают, что помощник OCR отсутствует** — при первом использовании `swiftc` (нужен Xcode) компилирует встроенный `assets/ocr.swift` в `~/Library/Caches/dsh-ios/bin/ocr`; ошибка содержит точный путь и подсказку. - **`ios_sim_ui_rows` не находит строк** — результат объясняет почему: слишком малая глубина (поднимите `max_depth`; на телефоне каждый более глубокий снимок стоит ~15–25 с), это не экран списка, или после глубокого чтения действительно нет информации о доступности. Поверхностное чтение никогда не выдаётся ошибочно за отсутствие доступности. - **`ios_sim_leaks` на симуляторах iOS 26.2** — на средах выполнения iOS 26.2 `leaks` из Xcode может не суметь проверить процессы симулятора с фатальными диагностиками вроде `Failed to get DYLD info` или ошибками minimal-corpse, даже с включённым режимом разработчика. Инструмент аккуратно деградирует: вы получаете сырую диагностику, цель всегда проверяется как возобновлённая, ничего не зависает. Исправления на стороне плагина нет — при возникновении попробуйте `mode: "memgraph"` или другую среду выполнения.. - **Поток останавливается сам** — это политика простоя, а не сбой: при нуле потребителей (панель закрыта, карточки не смонтированы, активных маршрутов нет) поток останавливается через 5 минут и перезапускается при следующем вызове инструмента или открытии панели. Упавший поток перезапускается в фоне в течение ~5 секунд. ## Разработка ```sh pnpm install pnpm run build # tsc хоста + бандл клиента → lib/ pnpm run typecheck ``` Смоук-тесты в `scripts/` прогоняют собранный `lib/` (только macOS для частей, которые загружают симулятор или общаются с телефоном по USB; задайте `DSH_IOS_SMOKE_SKIP_SIM=1`, чтобы пропустить эти части): | Скрипт | Что покрывает | | --- | --- | | `node scripts/dev-smoke.mjs` | Хост симулятора: разрешение бинарников, запуск потока, управление, keep-alive, dispose. | | `node scripts/dev-tools-smoke.mjs [--full-build]` | Основные инструменты на реальном симуляторе (плюс реальная сборка с `--full-build`). | | `node scripts/dev-routes-smoke.mjs` | Подписанные веб-маршруты: grant, прокси потока, скриншот, ретрансляция ws, ограждения, истечение. | | `node scripts/dev-card-smoke.mjs` | Карточки клиента: статический SSR (без ``), контракт status/capture, почти живая сетевая часть. | | `node scripts/dev-panel-smoke.mjs` | Компоненты панели, режимы размера, стили рамки, логика дока/триггера/капсулы (только статика). | | `node scripts/dev-logs-smoke.mjs` | snapshot/follow у `ios_sim_logs`, фильтры, лимиты, сбор процессов. | | `node scripts/dev-uitree-smoke.mjs` | Инструменты дерева UI: разрешение/конвейер загрузки AXe, селекторы, дерево и нажатие на реальном симуляторе. | | `node scripts/dev-debug-smoke.mjs` | Инструменты отладки: процессы, бэктрейс (lldb + sample), утечки, информация о приложениях. | | `node scripts/dev-preview-smoke.mjs` | Горячая перезагрузка превью: запуск, правка → горячая замена без перезапуска, восстановление после ошибок, остановка. | | `node scripts/dev-orphan-smoke.mjs` | Усыновление/возврат осиротевшего serve-sim после нештатного убийства хоста. | | `node scripts/dev-ocr-smoke.mjs` | Инструменты Vision-OCR: разрешение помощника, кэш компиляции swiftc, конвейер распознавания, маршрутизация tap-text. | | `node scripts/dev-wda-smoke.mjs` | Хост WebDriverAgent: разбор `ServerURLHere`, классификация сбоев, туннели, keep-alive (мок; опциональный живой прогон). | | `node scripts/dev-realdevice-smoke.mjs` | `xcrun devicectl` на подключённом по USB iPhone — ровно те пути кода, которые используют инструменты. | | `node scripts/dev-realstart-smoke.mjs` | Маршрут `/real-start`: ограждение, закодированные отказы, контроль сборки/запуска (статика). | | `node scripts/dev-realtools-smoke.mjs` | Бэкенды реального устройства для `ios_sim_screenshot` / `ios_sim_interact` / `ios_sim_ui_tree` / `ios_sim_tap_element` плюс `ios_real_start_wda`. | ## Экосистема - [DSH Android](https://github.com/ZSeven-W/dsh-android) — живой эмулятор Android или устройство по USB прямо в диалоге, полностью под управлением adb - [DSH Crew](https://github.com/ZSeven-W/dsh-crew) — делегировать задачи агентам DSH из Claude Code / Codex - [DSH Noema](https://github.com/ZSeven-W/dsh-noema) — долговременная память для DSH - [DSH OpenPencil](https://github.com/ZSeven-W/dsh-openpencil) — просматривать и редактировать документы `.op` прямо в диалоге ## Благодарности & лицензия - [serve-sim](https://github.com/EvanBacon/serve-sim) — Evan Bacon — движок трансляции симулятора (Apache-2.0; встроенная зависимость среды выполнения). - [AXe](https://github.com/cameroncooke/AXe) — Cameron Cooke — CLI доступности для инструментов дерева UI (MIT). - [WebDriverAgent](https://github.com/appium/WebDriverAgent) — WebDriver-сервер, который плагин собирает и запускает на реальных устройствах (лицензия BSD). - Архитектура вдохновлена плагином Codex «Build iOS Apps»; движок превью SwiftUI — чистая (clean-room) переработка публично задокументированного подхода, код Codex не копировался. - Полный список уведомлений см. в [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md). **Лицензия**: MIT