[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-23":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":23,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":32,"readmeContent":33,"aiSummary":34,"trendingCount":16,"starSnapshotCount":16,"syncStatus":35,"lastSyncTime":36,"discoverSource":37},23,"baguette","tddworks\u002Fbaguette","tddworks","Headless iOS Simulator manager\u002Ffarm + host-side input injection for iOS 26 — taps, swipes, multi-finger gestures, and 60 fps streaming","https:\u002F\u002Ftddworks.github.io\u002Fbaguette\u002F",null,"Swift",1382,67,7,5,0,277,490,83.5,"Apache License 2.0",false,"main",true,[25,26,27,28,29,30,31],"agent","cli","devicefarm","ios","simulator","simulatorkit","streaming","2026-06-11 04:00:17","\u003Cp align=\"center\">\n  \u003Cimg src=\"assets\u002Flogo.png\" alt=\"Baguette\" width=\"240\">\n\u003C\u002Fp>\n\n\u003Ch1 align=\"center\">Baguette\u003C\u002Fh1>\n\n\u003Cp align=\"center\">\u003Cem>Bon appétit.\u003C\u002Fem>\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  Headless iOS Simulator manager + host-side input injection for iOS 26.\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ftddworks\u002Fbaguette\u002Factions\u002Fworkflows\u002Fci.yml\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Ftddworks\u002Fbaguette\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg\" alt=\"CI\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fcodecov.io\u002Fgh\u002Ftddworks\u002Fbaguette\">\u003Cimg src=\"https:\u002F\u002Fcodecov.io\u002Fgh\u002Ftddworks\u002Fbaguette\u002Fbranch\u002Fmain\u002Fgraph\u002Fbadge.svg\" alt=\"Coverage\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ftddworks\u002Fbaguette\u002Freleases\u002Flatest\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Ftddworks\u002Fbaguette?sort=semver\" alt=\"Latest release\">\u003C\u002Fa>\n  \u003Ca href=\"LICENSE\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flicense\u002Ftddworks\u002Fbaguette\" alt=\"License\">\u003C\u002Fa>\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-6.1-orange?logo=swift\" alt=\"Swift 6.2\">\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FmacOS-15%2B-blue?logo=apple\" alt=\"macOS 15+\">\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FXcode-26-1575F9?logo=xcode\" alt=\"Xcode 26\">\n\u003C\u002Fp>\n\nA single Swift CLI — **`baguette`** — that creates \u002F boots \u002F shuts down\nsimulator devices, streams their screens at 60 fps, and injects taps\n\u002F swipes \u002F multi-finger touches without booting the Simulator.app GUI.\nOptionally serves a self-contained web UI on `localhost` so you can\ncontrol any booted simulator from a browser.\n\n## Demo\n\nhttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Fe904413f-16bb-4b3d-86d5-162333403cee\n\nhttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Fc49c9f4b-0e4b-47ea-9272-3223b1ac7739\n\nhttps:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002F65dc62ee-f0c7-48fb-9c57-5bd267c8c02f\n\n> The raw clip lives at [`assets\u002Fdemo.mp4`](assets\u002Fdemo.mp4) — drag\n> it into a GitHub web edit of this README to upload as a CDN-hosted\n> video and replace the line above with the auto-generated URL.\n\n- **Frame streaming** — MJPEG or H.264 \u002F AVCC over stdout or WebSocket.\n  Runtime-tunable bitrate \u002F fps \u002F scale.\n- **Host-HID input** — taps \u002F swipes \u002F streaming 1- and 2-finger gestures \u002F\n  home, lock, power, action, volume buttons \u002F Mac keyboard \u002F scroll wheel,\n  all through SimulatorKit's 9-argument\n  `IndigoHIDMessageForMouseNSEvent` from Xcode 26's preview-kit. No dylib\n  injection, no `DYLD_INSERT_LIBRARIES`, no per-app priming.\n- **Accessibility tree** — `baguette describe-ui` returns the on-screen\n  AX tree as JSON: per-node `role`, `label`, `value`, `identifier`, and\n  `frame` in the same device-point coordinates as `tap` \u002F `swipe`. Hit-test\n  mode (`--x --y`) returns the topmost node under a coordinate. Powered by\n  the private `AccessibilityPlatformTranslation` framework with a\n  `bridgeTokenDelegate` we install ourselves to make the dispatcher work\n  out of Simulator.app.\n- **Live unified-log stream** — `baguette logs --udid \u003CX>` streams the\n  booted simulator's `os_log` output line-by-line to stdout; `WS\n  \u002Fsimulators\u002F:udid\u002Flogs` does the same to a browser. Predicate \u002F\n  bundle-id filters supported.\n- **Standalone web UI** — `baguette serve` opens `http:\u002F\u002Flocalhost:8421\u002Fsimulators`\n  with a list page, live stream, gesture input, and DeviceKit-sourced\n  bezels for every simulator family.\n- **Device farm** — `http:\u002F\u002Flocalhost:8421\u002Ffarm` is an interactive\n  multi-device dashboard. Every booted simulator streams in a wall \u002F grid\n  \u002F list, with filtering and sorting; click a tile to focus it for\n  full-quality streaming + gesture and hardware-button input through the\n  same `GestureDispatcher` → `IndigoHIDInput` pipeline as the CLI.\n- **TDD non-negotiable, layered, mock-injected** — bounded-context\n  Domain \u002F Infrastructure \u002F App split; ~290 Swift Testing cases backed\n  by auto-generated `MockXxx` fakes for every external port (`Input`,\n  `Screen`, `Accessibility`, `LogStream`, `Chromes`, `DeviceHost`).\n  Adapters take `any DeviceHost` rather than the concrete\n  `CoreSimulators` so error-path branches are unit-tested without a\n  booted sim. `swift test` requires no simulator at all.\n\n## Install\n\n```bash\nbrew install tddworks\u002Ftap\u002Fbaguette\n```\n\nApple Silicon only. Requires Xcode 26 — `baguette` links against private\nSimulatorKit \u002F CoreSimulator frameworks shipped with Xcode.\n\n## Quickstart\n\n```bash\n# Start the web UI\nbaguette serve\n\n# Single-device dashboard — list, boot\u002Fshutdown, per-device stream pages\nopen http:\u002F\u002Flocalhost:8421\u002Fsimulators\n\n# Device farm — every booted simulator side-by-side, click to focus\nopen http:\u002F\u002Flocalhost:8421\u002Ffarm\n```\n\n`\u002Fsimulators` lists every simulator on the machine with Boot \u002F Shutdown\nbuttons; click any booted device to open its Stream page — live frames,\nmouse\u002Ftouch input, and the DeviceKit-sourced bezel.\n\n`\u002Ffarm` is the multi-device control surface. See\n[Device farm](#device-farm) below.\n\nHeadless from the terminal works too:\n\n```bash\nbaguette list\nbaguette boot --udid \u003CUDID>\nbaguette tap --udid \u003CUDID> --x 219 --y 478 --width 438 --height 954\n```\n\n## Build from source\n\n```bash\nmake           # release build via .\u002Fbuild.sh\nswift test     # run the test suite\n```\n\nHybrid build: SPM fetches dependencies (`ArgumentParser`, `Mockable`,\n`Hummingbird`, `HummingbirdWebSocket`); `swiftc` compiles everything\nwith an Objective-C bridging header targeting `arm64e-apple-macos26.0`,\nlinking `CoreSimulator`, `SimulatorKit`, `IOSurface`, `VideoToolbox`,\n`CoreGraphics`, `ImageIO` from Xcode's private frameworks.\n\n## CLI\n\n```\nbaguette \u003Ccommand> [options]\n\n  list [--json]                              List devices (default + custom sets;\n                                             --json emits {\"running\":[…],\"available\":[…]})\n  boot     --udid \u003CUDID>                     Boot headlessly\n  shutdown --udid \u003CUDID>                     Shutdown\n  stream   --udid \u003CUDID> [--fps 60] [--format mjpeg|avcc]\n                                             Stream frames on stdout\n  screenshot --udid \u003CUDID> [--output \u003Cpath>] [--quality 0.85] [--scale 1]\n                                             Capture one JPEG frame\n                                             (defaults to stdout)\n  describe-ui --udid \u003CUDID> [--x \u003Cpx> --y \u003Cpx>] [--output \u003Cpath>]\n                                             Dump on-screen accessibility tree\n                                             as JSON (full tree or hit-test);\n                                             frames are in DEVICE POINTS so\n                                             they pipe straight back into a tap.\n  logs --udid \u003CUDID> [--level info|debug|default]\n                     [--style default|compact|json|ndjson|syslog]\n                     [--predicate \u003CNSPredicate>] [--bundle-id \u003Cid>]\n                                             Stream the booted simulator's\n                                             unified log to stdout, line by line\n                                             (SIGINT to stop). Levels are the\n                                             three the iOS-runtime `log stream`\n                                             accepts — not host-`log`'s five.\n  input    --udid \u003CUDID>                     Read JSON gestures from stdin\n\n  # Standalone web UI on localhost. Serves \u002Fsimulators (single-device\n  # dashboard) and \u002Ffarm (multi-device dashboard) — both backed by the\n  # same WS endpoint and HID pipeline.\n  serve    [--port 8421] [--host 127.0.0.1] [--device-set \u003Cpath>]\n\n  # DeviceKit chrome \u002F bezel data.\n  chrome layout    --udid \u003CUDID>             Print bezel layout JSON\n  chrome composite --udid \u003CUDID>             Write composite PNG to stdout\n  chrome layout    --device-name \"iPhone 17 Pro\"\n  chrome composite --device-name \"iPhone 17 Pro\"\n\n  # One-shot gestures — same HID path as `input`, one gesture per\n  # invocation. Coordinates are in DEVICE POINTS; `width` \u002F `height`\n  # are the simulator's screen size in points.\n  tap     --udid … --x … --y … --width … --height … [--duration 0.05]\n  swipe   --udid … --startX … --startY … --endX … --endY … --width … --height …\n  pinch   --udid … --cx … --cy … --startSpread … --endSpread … --width … --height …\n  pan     --udid … --x1 … --y1 … --x2 … --y2 … --dx … --dy … --width … --height …\n  press   --udid … --button home|lock\n```\n\n## `baguette serve` — the web UI\n\n```bash\nbaguette serve --port 8421\n# [baguette] listening on http:\u002F\u002F127.0.0.1:8421\u002Fsimulators\n```\n\nOpen `http:\u002F\u002Flocalhost:8421\u002Fsimulators` in any browser. You get the\ndevice list (RUNNING \u002F AVAILABLE sections), Boot \u002F Shutdown buttons,\nand a Stream page per device with live frames + gesture input + the\nDeviceKit-sourced bezel.\n\nThe HTML is editable on disk — `Sources\u002FBaguette\u002FResources\u002FWeb\u002Fsim.html`\nopens directly in any browser via `file:\u002F\u002F` (preview mode), and points\nto its sibling `.js` files. Set `BAGUETTE_WEB_DIR` to override the\nserved root for live-iteration without rebuilding.\n\n### Routes (single resource tree, no `\u002Fapi\u002F` prefix)\n\n| Method | Path                                       | Backed by                    |\n|--------|--------------------------------------------|------------------------------|\n| `GET`  | `\u002F`                                        | 302 → `\u002Fsimulators`          |\n| `GET`  | `\u002Fsimulators`                              | list HTML                    |\n| `GET`  | `\u002Fsimulators.json`                         | list JSON `{running, available}` |\n| `GET`  | `\u002Fsimulators\u002F:udid`                        | stream HTML                  |\n| `POST` | `\u002Fsimulators\u002F:udid\u002Fboot`                   | `simulator.boot()`           |\n| `POST` | `\u002Fsimulators\u002F:udid\u002Fshutdown`               | `simulator.shutdown()`       |\n| `GET`  | `\u002Fsimulators\u002F:udid\u002Fchrome.json`            | DeviceKit bezel layout       |\n| `GET`  | `\u002Fsimulators\u002F:udid\u002Fbezel.png`              | rasterized bezel PNG         |\n| `GET`  | `\u002Fsimulators\u002F:udid\u002Fscreenshot.jpg`         | one-shot JPEG of the framebuffer (`?quality=&scale=`) |\n| `WS`   | `\u002Fsimulators\u002F:udid\u002Fstream?format=mjpeg|avcc` | live frames + control + input + `describe_ui` |\n| `WS`   | `\u002Fsimulators\u002F:udid\u002Flogs?level=&style=&predicate=&bundleId=` | live unified-log stream (one `{\"type\":\"log\",\"line\":…}` text frame per entry) |\n| `GET`  | `\u002Ffarm`                                    | device-farm HTML             |\n| `GET`  | `\u002Ffarm\u002F:file`                              | farm UI asset (`farm.css`, `farm-*.js`, …) |\n| `GET`  | `\u002F\u003Cfile>.{html,js,css}`                    | static UI asset              |\n\n### One bidirectional WebSocket per stream\n\nThe same WS carries everything for a viewing session:\n\n- **Server → Browser** — encoded binary frames (one per WS message).\n  - MJPEG: raw JPEG bytes per frame.\n  - AVCC: 1-byte tag + payload — `0x01` avcC description, `0x02` keyframe,\n    `0x03` delta, `0x04` JPEG seed (renders before H.264 IDR lands).\n- **Browser → Server** — text JSON, one line per message:\n  - Stream control: `{\"type\":\"set_bitrate\",\"bps\":N}` \u002F\n    `{\"type\":\"set_fps\",\"fps\":N}` \u002F `{\"type\":\"set_scale\",\"scale\":N}` \u002F\n    `{\"type\":\"force_idr\"}` \u002F `{\"type\":\"snapshot\"}`.\n  - Gesture input: same wire format as `baguette input` (see below).\n\nNo `\u002Fevent` POST, no UDID-keyed registry — the WS handler closure owns\nthe live stream + simulator handle for the duration.\n\n## Device farm\n\n```bash\nbaguette serve\nopen http:\u002F\u002Flocalhost:8421\u002Ffarm\n```\n\nA multi-device dashboard for the booted simulators on the host. Every\ndevice renders in a single page; the same WebSocket pipeline that powers\n`\u002Fsimulators\u002F:udid` drives every tile.\n\n**What it does**\n\n- **Three view modes** — Grid (compact thumbnails), Wall (large tiles\n  with bezels), and List (one-row-per-device with metadata). Toggle from\n  the header.\n- **Filter and sort** — by device family, OS version, run state. The\n  rail on the left holds filter state across view changes.\n- **Click to focus** — clicking any tile re-parents its `\u003Ccanvas>` into\n  a full-quality focused pane on the right. The thumbnail keeps streaming\n  at low bitrate; only the focused tile pays for full-rate frames. No\n  separate mirror video element — the same canvas appears in two places.\n- **Input on the focused tile** — gestures, hardware buttons (home \u002F\n  lock), and the pinch overlay all round-trip through `SimInputBridge`\n  → `GestureDispatcher` → `IndigoHIDInput`. Anything the CLI can drive,\n  the focused tile can drive.\n- **Bezels** — each tile renders with its DeviceKit bezel by default,\n  with a **9-slice composition fallback** for devices without a packaged\n  asset. Toggle to a raw (no-bezel) display mode from the tile menu.\n\n**What's served**\n\n`\u002Ffarm` is a thin HTML shell at `Resources\u002FWeb\u002Ffarm\u002Ffarm.html` that\nloads five IIFE component scripts from `\u002Ffarm\u002F\u003Cname>.js`:\n\n| Script           | Job                                             |\n|------------------|-------------------------------------------------|\n| `farm-views.js`  | Grid \u002F Wall \u002F List renderers (pure DOM)         |\n| `farm-tile.js`   | `FarmTile` — per-device thumbnail StreamSession |\n| `farm-focus.js`  | `FarmFocus` — focused-device pane               |\n| `farm-filter.js` | `FarmFilter` — filter state + sidebar wiring    |\n| `farm-app.js`    | `FarmApp` — orchestrator (boot, fetch, dispatch)|\n\n`BAGUETTE_WEB_DIR` overrides the served root, so you can iterate on the\nfarm UI without rebuilding — point it at `Sources\u002FBaguette\u002FResources\u002FWeb`\non disk and reload the browser.\n\n## Wire protocol — `baguette input`\n\nNewline-delimited JSON on stdin → `{\"ok\":true}` \u002F `{\"ok\":false,\"error\":…}`\non stdout, one ack per line.\n\n```json\n{\"type\":\"tap\",   \"x\":219, \"y\":478, \"width\":438, \"height\":954, \"duration\":0.05}\n{\"type\":\"swipe\", \"startX\":219,\"startY\":760, \"endX\":219,\"endY\":190,\n                 \"width\":438,\"height\":954, \"duration\":0.3}\n\n\u002F\u002F 1-finger streaming (phase-driven)\n{\"type\":\"touch1-down\", \"x\":219, \"y\":478, \"width\":438,\"height\":954}\n{\"type\":\"touch1-move\", \"x\":225, \"y\":485, \"width\":438,\"height\":954}\n{\"type\":\"touch1-up\",   \"x\":225, \"y\":485, \"width\":438,\"height\":954}\n\n\u002F\u002F 2-finger streaming (the primary pinch \u002F pan path for real-time gestures)\n{\"type\":\"touch2-down\", \"x1\":175,\"y1\":478, \"x2\":263,\"y2\":478, \"width\":438,\"height\":954}\n{\"type\":\"touch2-move\", \"x1\":150,\"y1\":478, \"x2\":288,\"y2\":478, \"width\":438,\"height\":954}\n{\"type\":\"touch2-up\",   \"x1\":150,\"y1\":478, \"x2\":288,\"y2\":478, \"width\":438,\"height\":954}\n\n\u002F\u002F Buttons (only home \u002F lock reach a working target on iOS 26.4)\n{\"type\":\"button\", \"button\":\"home\"}\n{\"type\":\"button\", \"button\":\"lock\"}\n\n\u002F\u002F Scroll\n{\"type\":\"scroll\", \"deltaX\":0, \"deltaY\":-50}\n\n\u002F\u002F One-shot pinch (server interpolates 10 steps)\n{\"type\":\"pinch\", \"cx\":219,\"cy\":478, \"startSpread\":60,\"endSpread\":240,\n                 \"width\":438,\"height\":954, \"duration\":0.6}\n\n\u002F\u002F One-shot parallel pan of two fingers\n{\"type\":\"pan\", \"x1\":175,\"y1\":478, \"x2\":263,\"y2\":478,\n               \"dx\":0,\"dy\":200, \"width\":438,\"height\":954, \"duration\":0.5}\n```\n\n**Coordinate convention.** All `x` \u002F `y` \u002F `startX` \u002F `endX` \u002F `x1` \u002F `x2`\nare in **device points** — same units as `width` and `height`. The HID\nadapter normalises internally before handing them to the C function.\nA \"tap at the centre of an iPhone 17 Pro Max\" is `x:219, y:478` (half of\n438×954), not `x:0.5, y:0.5`. The browser UI multiplies its normalized\ncoordinates by `width` \u002F `height` before serialising.\n\n### Not yet wired\n\n- `key` \u002F `type` — keyboard isn't on the host-HID path yet (preview-kit\n  recipe still WIP). Routes through external tools today.\n- `siri` button — crashes `backboardd` via every known Indigo path.\n\n## `baguette stream` — frame streaming\n\n```bash\nbaguette stream --udid \u003CUDID> --format avcc --fps 60 | ffplay -\n```\n\nOutputs length-prefixed binary frames on stdout. AVCC carries a 1-byte\ntype prefix per chunk:\n\n| Prefix | Meaning |\n|--------|---------|\n| `0x01` | avcC description — feed to `VideoDecoder.configure` |\n| `0x02` | Keyframe (IDR) AVCC payload |\n| `0x03` | Delta frame |\n| `0x04` | JPEG seed — paints before H.264 IDR lands |\n\nRuntime control: while streaming, write one JSON line per command to\nstdin to retune without restarting.\n\n```json\n{\"type\":\"set_bitrate\",\"bps\":4000000}\n{\"type\":\"set_fps\",\"fps\":30}\n{\"type\":\"set_scale\",\"scale\":2}\n{\"type\":\"force_idr\"}\n{\"type\":\"snapshot\"}\n```\n\n## `baguette chrome` — DeviceKit bezel data\n\n```bash\nbaguette chrome layout --device-name \"iPhone 17 Pro\" | jq .\nbaguette chrome composite --device-name \"iPhone 17 Pro\" > iphone17pro.png\n```\n\nReads Apple's own DeviceKit chrome bundles\n(`\u002FLibrary\u002FDeveloper\u002FDeviceKit\u002FChrome\u002F`) and emits the bezel layout\nJSON or rasterizes the composite PDF to PNG. The `serve` page uses\nthis for every simulator family — no hand-curated bezel table to keep\nin sync.\n\n## Source layout\n\nBounded contexts mirror across `Domain\u002F` and `Infrastructure\u002F` so a\nfeature lives in one place across both layers.\n\n```\n.\n├── Makefile                          wraps build.sh\n├── build.sh                          hybrid SPM + swiftc, arm64e-apple-macos26.0\n├── Package.swift                     SPM manifest\n│\n├── Sources\u002FBaguette\u002F\n│   ├── App\u002F                          CLI dispatch + use-case orchestration\n│   │   ├── RootCommand.swift\n│   │   ├── GestureDispatcher.swift   JSON line → Gesture → Input\n│   │   ├── ReconfigParser.swift      runtime stream-control parser\n│   │   ├── Logger.swift\n│   │   └── Commands\u002F                 one file per CLI subcommand\n│   │       (list \u002F boot \u002F shutdown \u002F stream \u002F input \u002F serve \u002F chrome \u002F\n│   │        screenshot \u002F describe-ui \u002F logs \u002F gesture one-shots \u002F\n│   │        keyboard \u002F press)\n│   │\n│   ├── Domain\u002F                       pure Swift, no Apple private APIs\n│   │   ├── Common\u002F                   CoordinateTypes (Point, Size, Rect, Insets,\n│   │   │                             HIDUsage, DeviceButton)\n│   │   ├── Simulator\u002F                Simulator value type + Simulators aggregate +\n│   │   │                             DeviceHost port (the seam adapters depend on)\n│   │   ├── Input\u002F                    Input port + Gesture \u002F GestureRegistry +\n│   │   │                             Tap \u002F Swipe \u002F Touch1 \u002F Touch2 \u002F Press \u002F\n│   │   │                             Scroll \u002F Pinch \u002F Pan \u002F Key \u002F TypeText \u002F\n│   │   │                             Keyboard\n│   │   ├── Screen\u002F                   Screen port (frame source)\n│   │   ├── Stream\u002F                   Stream port + StreamConfig \u002F StreamFormat\n│   │   │                             + Envelope (MJPEG \u002F AVCC framing)\n│   │   ├── Chrome\u002F                   Chromes aggregate + DeviceChrome \u002F\n│   │   │                             DeviceProfile (bezel layout)\n│   │   ├── Accessibility\u002F            AXNode value type + Accessibility port\n│   │   │                             (on-screen UI tree)\n│   │   └── Logs\u002F                     LogFilter value type + LogStream port\n│   │                                 (live unified-log feed)\n│   │\n│   ├── Infrastructure\u002F               concrete @Mockable port impls (private-API\n│   │                                 code lives ONLY here)\n│   │   ├── Simulator\u002F                CoreSimulators (CoreSimulator + SimulatorKit\n│   │   │                             ObjC bridge); conforms to Simulators +\n│   │   │                             DeviceHost\n│   │   ├── Input\u002F                    IndigoHIDInput (9-arg\n│   │   │                             IndigoHIDMessageForMouseNSEvent + button +\n│   │   │                             HIDArbitrary + keyboard paths)\n│   │   ├── Screen\u002F                   SimulatorKitScreen (framebuffer callbacks),\n│   │   │                             ScreenSnapshot (one-shot JPEG capture)\n│   │   ├── Stream\u002F                   MJPEG \u002F AVCC encoders, JPEG \u002F H.264\n│   │   │                             encoders, Scaler, SeedFilter, Stdout \u002F\n│   │   │                             WebSocket FrameSinks, ControlChannel\n│   │   ├── Chrome\u002F                   LiveChromes + ChromeStore \u002F\n│   │   │                             FileSystemChromeStore + PDFRasterizer\n│   │   ├── Accessibility\u002F            AXPTranslatorAccessibility (AXPTranslator +\n│   │   │                             TokenDispatcher bridge for the iOS-26\n│   │   │                             out-of-Simulator.app accessibility path)\n│   │   ├── Logs\u002F                     SimDeviceLogStream (shells out to\n│   │   │                             `xcrun simctl spawn` for the in-sim\n│   │   │                             `\u002Fusr\u002Fbin\u002Flog stream` child)\n│   │   └── Server\u002F                   Server (Hummingbird HTTP + WS) + WebRoot\n│   │\n│   └── Resources\u002FWeb\u002F                static UI for `serve`\n│       ├── sim.html                  list + stream entry, opens via file:\u002F\u002F\n│       ├── sim-list.js               list page renderer\n│       ├── sim-stream.js             stream-page orchestrator\n│       ├── sim-stream.html           stream view markup\n│       ├── sim-input.js              SimInput \u002F MouseGestureSource \u002F PinchOverlay\n│       ├── sim-input-bridge.js       SimInput → baguette wire-format mapper\n│       ├── sim-native.js             focus-mode (single-sim fullscreen) view\n│       ├── frame-decoder.js          MJPEG \u002F AVCC strategy\n│       ├── device-frame.js           bezel + screen DOM\n│       ├── stream-session.js         WebSocket + paint loop\n│       ├── capture-gallery.js        screenshot fetch + thumbs\n│       └── farm\u002F                     multi-device dashboard (farm.html, farm.css,\n│                                     farm-tile.js, farm-grid.js, …)\n│\n└── Tests\u002FBaguetteTests\u002F              mirrors Sources\u002F contexts\n    ├── App\u002F                          GestureDispatcher \u002F ReconfigParser \u002F\n    │                                 Logger \u002F Commands (CommandParsing,\n    │                                 ChromeCommand) tests\n    ├── Simulator\u002F                    Simulator \u002F Simulators \u002F DeviceHost tests\n    ├── Input\u002F                        Gesture \u002F GestureRegistry \u002F Keyboard \u002F\n    │                                 IndigoHIDInput error-path tests\n    ├── Screen\u002F                       (none yet — Screen port covered via\n    │                                 mocks in Server tests)\n    ├── Stream\u002F                       Envelope \u002F StreamConfig \u002F StreamFormat tests\n    ├── Server\u002F                       BezelRoutes \u002F WebRootSubdir tests\n    ├── Chrome\u002F                       DeviceChrome \u002F DeviceProfile \u002F LiveChromes \u002F\n    │                                 CoreGraphicsPDFRasterizer \u002F integration tests\n    ├── Accessibility\u002F                AXNode \u002F Accessibility port \u002F\n    │                                 AXPTranslatorAccessibility error-path tests\n    └── Logs\u002F                         LogFilter \u002F LogStream port \u002F\n                                      SimDeviceLogStream error-path tests\n```\n\n## Testing\n\n**TDD is non-negotiable** — every behaviour change to a Domain or\nInfrastructure type lands in a failing `@Test` under `Tests\u002F` first,\nthen the smallest implementation that turns it green, then refactor.\nRead `CLAUDE.md`'s \"TDD is non-negotiable\" pre-implementation gate\nbefore contributing — that's the project's primary rule and it\noverrides \"the change is small\" \u002F \"I'll add the test after\".\n\n~290 tests using **Swift Testing** (`@Suite`, `@Test`, `#expect`),\nnot XCTest. Chicago-school state-based: every external boundary is\nan `@Mockable` protocol (`Input`, `Screen`, `Accessibility`,\n`LogStream`, `Chromes`, `DeviceHost`); tests substitute\nauto-generated `MockXxx` fakes, and assert on returned values rather\nthan recorded calls.\n\nAdapters that talk to private SimulatorKit \u002F CoreSimulator \u002F\nAccessibilityPlatformTranslation symbols (`IndigoHIDInput`,\n`AXPTranslatorAccessibility`, `SimDeviceLogStream`,\n`SimulatorKitScreen`) take `any DeviceHost` rather than the concrete\n`CoreSimulators` aggregate, so their error-path branches —\n`simulatorNotBooted`, idempotent `stop`, host-deallocated, etc. —\nare unit-tested via `MockDeviceHost` without needing a real booted\nsimulator. The successful private-API call path stays\nintegration-only — manually smoke-tested through the CLI and serve\nUI against a booted iOS sim.\n\n```bash\nswift test                                              # all tests\nswift test --filter Simulators                          # one suite\nswift test --filter \"GestureRegistry\u002Fparses tap\"        # one test\n```\n\nThe `MOCKING` compilation flag is set under `.debug` only, so release\nbuilds (via `.\u002Fbuild.sh`) carry no mock code.\n\n## Why this works on iOS 26.4 when older tools don't\n\niOS 26 changed `SimulatorHID`'s wire format. Public tools like `idb` and\n`AXe` call `IndigoHIDMessageForMouseNSEvent` with the old 5-argument\nsignature; those messages now route to a pointer-service target that\nsilently drops or crashes `backboardd`. Baguette uses the **9-argument\nsignature from Xcode 26's preview-kit**, which routes through digitizer\ntarget `0x32` — the target iOS 26 still honours.\n\nThat single calling-convention change is the entire difference. The\nrecipe is heavily commented in `Sources\u002FBaguette\u002FInfrastructure\u002FInput\u002FIndigoHIDInput.swift`,\nand the layered design is documented in\n[`docs\u002FARCHITECTURE.md`](docs\u002FARCHITECTURE.md).\n\n## License\n\nApache License 2.0 — see [`LICENSE`](LICENSE).\n","Baguette 是一个无头 iOS 模拟器管理工具，支持在宿主机上注入输入操作（如点击、滑动、多指手势等）并以60帧每秒的速度进行屏幕流传输。它采用Swift编写，通过命令行界面实现模拟器设备的创建、启动和关闭，并能够将屏幕内容以MJPEG或H.264\u002FAVCC格式输出到标准输出或WebSocket。此外，Baguette还提供了对iOS应用UI树的访问能力，可以获取屏幕上每个元素的角色、标签、值及位置信息，便于自动化测试场景下的精准控制。该项目适用于需要高效执行iOS应用自动化测试、远程调试或展示iOS应用运行状态的场合。",2,"2026-06-11 02:30:30","CREATED_QUERY"]