# vphone local development kit (macOS PoC)

This is a small Python 3.9+ standard-library wrapper for the current upstream source
commit `3f7011406722576fb19bffbc8c30d8aa4c4916af`. It is designed for local
debugging, not unattended installation or a production integration.

It does not install Homebrew/Xcode/Python, download IPSWs, change SIP/AMFI/NVRAM,
or start a real VM unless an operator supplies `--execute`. `bootstrap
--fetch-source --execute` can explicitly clone/fetch the official source at the
pinned SHA; no current checkout is assumed. VM files are isolated in `.local-data/`, via
both `VPHONE_ROOT` and `VPHONE_LIBRARY_ROOT`, never `~/.vphone`.

The upstream flow is JB-only: `vm create` performs firmware preparation,
patching, online restore, CFW installation, then a temporary boot to ping
`vphoned`; it stops that verification boot. It requires explicit local iPhone
and cloudOS IPSWs. Current source evidence only validates iPhone17,3 26.6.2
(23G90) or 27.0 (24A435) with cloudOS 26.4 (23E5207q); it is not a general
firmware compatibility claim.

## Commands

```sh
# Host/source facts; append --preflight only when an upstream CLI already exists.
./vphone-local doctor --source /path/to/vphone-cli

# Reuse a distributed/source-built CLI (does not install it).
./vphone-local bootstrap --reuse-cli /absolute/path/to/vphone-cli

# Explicitly fetch the pinned source and build it. The first command only prints argv.
./vphone-local bootstrap --fetch-source --source /private/tmp/vphone-cli --dry-run
./vphone-local bootstrap --fetch-source --source /private/tmp/vphone-cli --execute

# Exact local IPSWs are required. First prints a safe dry-run.
./vphone-local --cli /absolute/path/to/vphone-cli create dev17 \
  --iphone-source /firmware/iPhone17,3_26.6.2_23G90.ipsw \
  --cloudos-source /firmware/cloudOS_26.4_23E5207q.ipsw --dry-run

# A real launch is explicit and the API is restricted to loopback.
./vphone-local --cli /absolute/path/to/vphone-cli launch dev17 --dry-run
./vphone-local --cli /absolute/path/to/vphone-cli launch dev17 --execute
./vphone-local --cli /absolute/path/to/vphone-cli stop dev17 --execute

# Read the launched guest API through loopback, with the selected timeout.
./vphone-local health --api-listen 127.0.0.1:8765
```

`create` runs host-condition checks and upstream `host preflight` before any
firmware work. It passes `--root-popup` by default, so the CFW phase uses the
upstream macOS authentication dialog rather than failing without a terminal.
This is intentionally an operator-visible authorization step, not a password
prompt the kit can silently bypass.

`launch` uses upstream `--api-listen 127.0.0.1:8765`, exposing the documented
HTTP/WebSocket vphoned API (`/v1/health`, `/openapi.json`, `/v1/rpc`) only to
the local machine. The API has no built-in authentication; this kit refuses
non-loopback addresses.

An executed `launch` remains in the foreground and streams VM logs; it has no
wrapper timeout because killing only the launcher could leave a guest behind.
Use Ctrl-C in that terminal (shared with the upstream VM process), or run the
separate `stop` command from another terminal. Its live terminal output is not
duplicated into a kit log file.

The GUI VM also creates `<data-root>/VMs/<name>/vphone.sock`. The current source
implements one JSON line per Unix-socket connection. It supports a full-screen
host screenshot and pixel-coordinate tap, so this kit sends that actual protocol:

```sh
./vphone-local screenshot dev17 --output /private/tmp/dev17.png --dry-run
./vphone-local screenshot dev17 --output /private/tmp/dev17.png
./vphone-local touch dev17 645 1398
```

The screenshot/touch commands require an already-running GUI VM; they do not
use an undocumented TCP socket. `vphone.sock` is local host automation, while
the primary guest integration is the opted-in HTTP API above.

Every executed external command except the deliberately foreground `launch`
uses an argument array, has a timeout, captures combined output under
`.local-data/logs/`, and reports the retained log path on failure. Diagnose a
preserved log without making any host change:

```sh
./vphone-local diagnose --log .local-data/logs/20260924-120000-vm-create.log
```

`diagnose` reports matching lines as candidates, never a confirmed root cause.
Normal “AMFI”, “entitlement”, or “memory pressure” status text is ignored. A
bare `SIGKILL`/`Killed` remains unknown, because it can come from an operator,
watchdog, or process supervisor.

The disk figure from `doctor` is calculated from the nearest existing parent of
the selected `--data-root`, so it follows the volume where VM data will be
created instead of assuming the kit's own volume. It is only available-space
context, not a guarantee that the large firmware/restore workflow will fit.

## 中文操作说明与边界

这个包是本地调试 PoC，**没有做真机或真实 VM 端到端验证**。`doctor` 会读取
macOS/Apple Silicon、磁盘余量、内存、Xcode iPhoneOS SDK 和可能的嵌套虚拟化标志；
`create` 遇到明确主机阻断条件会退出。它不会替用户关闭 SIP/AMFI、设置 NVRAM、安装
brew 或下载大固件。

执行顺序是：`doctor` → `bootstrap --fetch-source --execute`（或复用已有 CLI）→
提供两个本地 IPSW → `create ... --execute` → `launch ... --execute` → `health`。
创建过程默认会弹出系统授权窗口；这一步是上游 CFW 安装的实际要求，不能安全地脚本化
成自动输入密码。当前 kit 还**没有封装 IPA 安装**；可在启动后使用上游
`/openapi.json`、`/v1/rpc` 或单独的受审计客户端实现，不应把未验证的安装流程伪装成可用。

## Source evidence used

- `README.md`, `docs/guides/host-setup.md`, and `docs/guides/create-and-run.md`
  at the pinned commit define the supported JB pipeline and source build command
  `zsh Scripts/build.sh`.
- `research/vphoned_http_api.md` defines VSOCK 1339, the opt-in loopback HTTP
  forwarding, `/v1/health`, `/openapi.json`, and `/v1/rpc`.
- `Sources/VPhoneVirtualMachineKit/VPhoneHostAutomationServer.swift` defines
  `vphone.sock` as one JSON line in/out, including `screenshot` and `tap`.

Run the local tests with `python3 -m unittest discover -s tests -v`.
