# 策展 · X (Twitter) 🔥

> 📖 本站完整內容索引（documentation index）：[llms.txt](/llms.txt)

> 作者：Jason Kneen (@jasonkneen) · 平台：X (Twitter) · 日期：2026-04-22

> 原始來源：https://x.com/jasonkneen/status/2046596093077536843

## 中文摘要

Agent-Simulator推出，串流iOS模擬器至瀏覽器，支持Agent互動與React Native除錯。

Agent-Simulator是一個開源工具，基於MCP協定，將iOS模擬器畫面串流至瀏覽器，讓使用者或AI Agent無需移動macOS游標，即可點擊、滑動、輸入，並檢視真實程式碼來源。開發者Jason Kneen強調其同時服務RN/Expo開發者、QA測試與AI Agent三類使用者，目前iOS版已可用，Android版開發中，呼籲星標、分享與貢獻，保持開源精神。

**三大目標客群**
- RN/Expo開發者：提供類Figma「圖層面板」，點擊運行中的App.tsx:42即跳轉真實來源。
- QA與示範流程：無XCUITest痛點的腳本化模擬，支持accessibility-label點擊、滑動、鍵盤輸入與截圖。
- AI Agent（如Claude Desktop、OpenAI Agents SDK、Cursor）：透過MCP暴露完整瀏覽器功能，讓Agent「看見」畫面並「行動」。

**核心功能**
- **無游標輸入**：透過axe → FBSimulatorHID → CoreSimulator，每個點擊/滑動/按鍵皆像素精準，無需Simulator.app焦點或macOS游標移動，支持任意縮放。
- **驅動任意iOS App**：點擊、拖曳、滑鼠滾輪滾動、多工切換、主畫面、鎖定、鍵盤直通，適用Settings、Maps、Messages等非RN App。
- **iOS無障礙樹**：啟動即由axe describe-ui填充，每個畫面元素含label、role與frame，點擊前即可檢視。
- **React元件樹**：RN App搭配metro plugin，檢視渲染元件獲完整fiber堆疊與真實來源路徑（React 19 _debugStack + Metro /symbolicate）。
- **真實程式碼面板**：選取元件後，屬性面板抓取實際檔案並高亮目標行，支持自訂程式碼、RN Libraries與Expo shims。
- **MCP橋接**：15項工具如sim_tree、sim_tap_by_label、sim_swipe、sim_type、sim_inspect、sim_source等，將瀏覽器全功能暴露給Agent。

**系統架構**
工具分三層架構，驅動單一iOS模擬器：

```
瀏覽器UI ── WS + HTTP ── server.js (Node) ── WS/stdin ── sim-server (Rust) ── iOS Simulator (axe + simctl)
                          │                     │
                          └─ MCP client ── stdio ─┘
```

- **sim-server (Rust)**：經simctl io screenshot擷取畫面編碼MJPEG，提供/stream.mjpeg、/snapshot.jpg、/api/tree與/health，從stdin讀取指令並shell axe。
- **server.js (Node)**：協調sim-server，服務Vite UI，暴露/api/config、/api/tree、/api/source，橋接瀏覽器與MCP WebSocket客戶端，代理Metro /symbolicate。
- **web-app (React + shadcn + Tailwind)**：深色/淺色主題、可調整面板、鍵盤擷取、拖曳滑動、滾輪滾動。

觸控注入流程：瀏覽器點擊經WS → server.js → stdin → sim-server → exec axe tap -x… -y… → FBSimulatorHID，座標以[0,1]比例End to End傳遞，sim-server轉換為device points（基於axe describe-ui根AXFrame，5秒TTL，旋轉時失效）。

**介面佈局**
| 區域 | 內容 |
|------|------|
| **標頭** | 裝置晶片、串流+橋接狀態丸、Inspect切換、主畫面/多工/鎖定/旋轉、面板切換、主題選單。 |
| **圖層面板（左）** | 切換iOS無障礙樹（自動填充）與React元件樹（檢視時填充），點擊選取、懸停高亮、畫面內點擊自動展開祖先。 |
| **模擬器畫布** | 即時MJPEG，驅動模式隱藏原生游標換圓形指標，點擊現脈衝環、拖曳變滑動、滾輪滾動、鍵盤輸入焦點欄位；Inspect模式換十字準星與選取覆蓋。 |
| **屬性面板（右）** | 選取圖層無障礙屬性、React元件名+來源、高亮JSX呼叫點或元件定義程式碼視窗。 |
| **狀態列** | UDID、模式旗標、上次檢視幀數、鍵盤快捷鍵提示。 |

**鍵盤快捷鍵**
- I：切換Inspect（無RN橋接時停用）。
- Esc：取消Inspect/解除選取固定。
- 其他按鍵（畫布焦點時）：直送模擬器（適用任意文字欄位）。

**MCP橋接細節**
mcp/server.mjs為獨立Model Context Protocol伺服器，經stdio與MCP主機溝通，WebSocket橋接agent-simulator伺服器，暴露15工具：

| 工具 | 用途 |
|------|------|
| sim_info | 裝置UDID/名稱/串流URL/裝置點尺寸。 |
| sim_tree | 完整iOS無障礙樹，flat: true回傳標籤元素清單供LLM低成本脈絡。 |
| sim_tap | 點擊(x, y)模擬器比例座標。 |
| sim_tap_by_label | 依label/value（選type篩選）查AX元素並點中心，抗佈局變動。 |
| sim_swipe | 單呼叫原生滑動，含durationMs。 |
| sim_type | 輸入可印文字至焦點TextField。 |
| sim_key | 按USB-HID鍵碼（Return=40、Backspace=42、Esc=41、箭頭80–83）。 |
| sim_button | home/lock/power/side-button/siri/apple-pay。 |
| sim_multitask | 開啟App切換器。 |
| sim_screenshot | 回傳當前幀為MCP image內容。 |
| sim_inspect | 檢視(x, y) RN元件，回傳來源symbolicate堆疊。 |
| sim_source | 讀取file:line周圍程式碼視窗（絕對路徑）。 |
| sim_select_by_source | 給fileName+line，網格探測匹配渲染元件。 |
| sim_subscribe_selections | 串流inspectResult事件為MCP記錄通知。 |
| sim_unsubscribe_selections | 停止上述。 |

**MCP客戶端設定範例**
Claude Desktop於~/Library/Application Support/Claude/claude_desktop_config.json新增：
```jsonc
{
  "mcpServers": {
    "agent-simulator": {
      "command": "node",
      "args": ["/absolute/path/to/agent-simulator/mcp/server.mjs"],
      "env": { "SIM_PREVIEW_URL": "http://localhost:3200" }
    }
  }
}
```
其他MCP主機（如OpenAI Agents SDK、Cursor）spawn node /path/to/mcp/server.mjs，設SIM_PREVIEW_URL指向運行伺服器。

**Agent流程範例**
1. sim_tree flat:true → 看畫面所有元素。
2. sim_tap_by_label "+" → 點擊計數器加號。
3. sim_tap_by_label "Your name" type:"TextField"。
4. sim_type "hello agent"。
5. sim_key 40 → Return。
6. sim_inspect x:0.86 y:0.24 → 回傳App.tsx:42。
7. sim_source file:".../App.tsx" line:42 → 讀JSX。

**快速啟動（1分鐘）**
```bash
git clone https://github.com/jkneen/agent-simulator
cd agent-simulator
bun install
(cd sim-server && cargo build --release)
(cd web-app && bun install && bun run build)
xcrun simctl boot "iPhone 17 Pro" || true
open -a Simulator
bun start
open http://localhost:3200
```
UI自動附加已啟動模擬器，開Settings/Maps等即可驅動；左側iOS圖層樹由無障礙API填充，RN App載入inspector bridge後React樹才激活。

**一指令示範（最有趣）**
```bash
bun demo
```
自動：啟動iPhone模擬器、Metro於examples/expo-demo:8081、Expo Go載入exp://127.0.0.1:8081、agent-simulator:3200、開瀏覽器。Ctrl-C清理。操作：點擊預覽驅動（脈衝環+圖層展開）、I鍵Inspect（懸停/點擊React元件填屬性面板）、點+開examples/expo-demo/App.tsx:42高亮<Text style={styles.pillText}>+</Text>。

旗標：--no-open跳瀏覽器、--port=3300改端口、--metro-port=8082改Metro、--device=<UDID>指定模擬器。

**整合至自有RN/Expo App**
metro.config.js：
```js
const { getDefaultConfig } = require("expo/metro-config");
const { withAgentSimulator } = require("agent-simulator/runtime/metro-plugin");
module.exports = withAgentSimulator(getDefaultConfig(__dirname));
```
bun add -D agent-simulator。或index.ts匯入前registerRootComponent：
```ts
import "agent-simulator/runtime/inspector-bridge";
```
App啟動後，工具列BRIDGE丸轉綠，檢視點擊產生完整堆疊+來源。

**串流品質與FPS上限**
工具列Quality下拉，五預設+FPS/JPEG品質/縮放/擷取模式滑桿。切換經WS setCapture重啟sim-server，半秒內瀏覽器<img>重訂閱。

| 預設 | 目標FPS | 解析度 | 模式 | 備註 |
|------|---------|--------|------|------|
| Eco | 2 | 300×650 | MJPEG | 省電背景監控。 |
| Balanced | 3 | 400×870 | MJPEG | 預設，匹配CSS渲染尺寸。 |
| Smooth | 最高10 | 400×870 | MJPEG | 適合滾動。 |
| Max | 最高30 | 400×870 | MJPEG | MJPEG路徑上限。 |
| Fluid | 最高60 | 400×870 | BGRA + keepalive | 實驗性，見限制。 |

點擊精度獨立於解析度，皆用[0,1]比例伺服器轉device points，低解析僅損畫面像素，非瞄準。

**真實FPS數據（iPhone 17 Pro模擬器，M系列Mac）**
| 路徑 | 要求 | 實際 |
|------|------|------|
| axe screenshot（單張） | — | 280–370 ms/張，~3 fps上限。 |
| axe stream-video --format raw --fps 30 | 30 | ~5–10 fps（axe截圖迴圈瓶頸）。 |
| axe stream-video --format bgra | 60 | 首幀後停滯，FBVideoStreamConfiguration硬編framesPerSecond: nil，iOS sim IOSurface回呼沉默。 |

Fluid 60 fps為願景，架構就位，但axe當前無法達標。解法：(1) fork axe傳framesPerSecond至BGRA；(2) Swift helper直連FBSimulatorControl.xcframework驅SimDevice/SimDeviceIOClient，皆半日工程，後端換入即替換。

Fluid keepalive：BGRA單幀後無更新，sim-server並行axe screenshot，300 ms無幀即PNG解碼→JPEG廣播，避免空白。閒置~3 fps，滾動BGRA貢獻，keepalive沉默。最差不掉0 fps。

環境變數：SP_FPS=10 SP_QUALITY=60 SP_SCALE=0.33 SP_CAPTURE=mjpeg bun start；SP_CAPTURE=bgra強制BGRA。

**需求與安裝**
- macOS + Xcode + 至少一iOS模擬器。
- Node ≥18（或Bun）。
- Rust toolchain（建sim-server一次）。
- axe：brew install cameroncooke/axe/axe。
- RN/Expo App僅React檢視需agent-simulator metro plugin，其他功能通用任意iOS App。

**開發提示**
- Agent腳本直用axe裝置點座標，UI處理比例轉換。
- axe describe-ui參考：axe describe-ui --udid <UDID> | jq '.[0]'。
- inspector-bridge.js改動無效Metro快取，重啟expo start --clear。
- SP_FPS/SP_QUALITY調MJPEG（預設fps=3 q=55）。

**開發指令**
```bash
(cd sim-server && cargo build --release)  # Rust改動後
(cd web-app && bun run build)             # UI改動後
bun mcp                                   # 獨立MCP伺服器
npx @modelcontextprotocol/inspector node mcp/server.mjs  # 監控MCP流量
```

專案佈局：
```
agent-simulator/
├── server.js              Node協調、WS橋接、HTTP
├── scripts/demo.mjs       一鍵示範啟動
├── sim-server/            Rust MJPEG + axe驅動
├── runtime/               RN metro plugin + inspector bridge
├── web-app/               Vite + React + shadcn UI
├── web/                   舊單檔UI (/classic)
├── mcp/                   MCP伺服器 (15工具)
├── examples/expo-demo/    預配plugin Expo App
└── LICENSE                AGPL-3.0-or-later
```

**React來源解析（React 19）**
纖維._debugSource移除，來源藏_fiber._debugStack（Error堆疊字串指bundle-URL行/欄）。檢視時：
1. inspector-bridge解析_debugStack，收集每纖維最多12候選bundleFrames。
2. server.js批POST至localhost:8081/symbolicate，一次往返挑非React createElement/jsxDEV內第一候選。
3. UI收stack[i].source為真實絕對檔案路徑，涵蓋使用者元件、RN內部（RCTView、ScrollView）、Expo shim。

**API細節**
- GET /api/tree：代理axe describe-ui --udid，UI啟動/刷新拉取，MCP sim_tree包裝。
- GET /api/source?file=ABS&line=N&context=M：讀line周圍M行，回{file, lines, startLine0, endLine0, targetLine0, language}，驅UI程式碼面板與sim_source。

**授權與未來**
AGPL-3.0-or-later。若嵌入商業產品或需其他授權，開issue討論雙授權。Android版開發中，需整理包裝成CodeSurf等擴充套件。

## 標籤

Agent, MCP, 開源專案, iOS, 自動化, Agent-Simulator, React Native, Expo
