Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `SIM_USE_HID_TRANSPORT=indigo|dtuhid` debug override to force a specific iOS HID transport (default: automatic per-boot selection). The per-UDID daemon keeps the environment it was spawned with — combine with `SIM_USE_NO_DAEMON=1` or restart the daemon for ad-hoc experiments.
- `describe-ui --no-raw` (top-level, `ios describe-ui`, and `android describe-ui`): with `--json`, omit the raw accessibility tree from the envelope. `data.raw` typically dominates the payload on real app screens and is only useful for debugging sim-use itself; `outline` / `entries` / `lists` are unaffected.
- *Keeping output small* section in `skills/sim-use/SKILL.md`: steers agents to prefer the text outline, pair `--json` with `--no-raw`, verify via outline instead of screenshots, reuse the verify read as the next observe, and batch known sequences.
- Viewer: `GET /api/snapshot` now forwards the CLI's calibrated interface orientation as `screen.orientation` (omitted when `describe-ui` reports none — Android, legacy daemons), and the SPA tags a rotated screen next to the W×H readout, e.g. `874×402 (landscape-right)`. (#57)

### Changed

Expand Down
11 changes: 10 additions & 1 deletion Sources/SimUse/Viewer/ViewerAPIHandlers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,16 @@ struct ViewerAPIHandlers {
}
let data = (envelope["data"] as? [String: Any]) ?? [:]
let outline = data["outline"] as? String
let screen = parseScreenFromOutline(outline)
var screen = parseScreenFromOutline(outline)
// `describe-ui --json` carries the calibrated interface
// orientation whenever calibration ran (issue #38); forward
// it verbatim rather than parsing the `(landscape-right)`
// suffix back out of the outline header. Absent on Android
// and legacy daemons — the key is simply omitted then,
// matching the CLI envelope semantics.
if let orientation = data["orientation"] as? String {
screen?["orientation"] = orientation
}
var payload: [String: Any] = [
"ok": true,
"capturedAt": iso8601Now(),
Expand Down
23 changes: 23 additions & 0 deletions Tests/ViewerAPIHandlersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,5 +240,28 @@ struct ViewerAPIHandlersTests {
#expect(screen["appLabel"] as? String == "SampleApp")
#expect(screen["width"] as? Int == 874)
#expect(screen["height"] as? Int == 402)
// No `data.orientation` in the envelope → no `orientation`
// key in the screen payload (issue #57).
#expect(screen["orientation"] == nil)
}

@Test("snapshot: forwards data.orientation into the screen payload")
func snapshotForwardsOrientation() async throws {
let envelope = """
{"ok":true,"data":{"platform":"ios","orientation":"landscape-right","outline":"App: SampleApp 874x402 (landscape-right)\\n\\n[Top y<120]\\n","entries":[],"lists":[]}}
"""
let (handlers, cleanup) = try makeHandlers(stdout: envelope, exitCode: 0)
defer { cleanup() }

let response = await handlers.snapshot(getRequest(query: ["deviceId": "TEST-UDID"]))

#expect(response.status == 200)
let body = try jsonBody(response)
let screen = try #require(body["screen"] as? [String: Any])
#expect(screen["orientation"] as? String == "landscape-right")
// The rest of the screen payload is unaffected.
#expect(screen["appLabel"] as? String == "SampleApp")
#expect(screen["width"] as? Int == 874)
#expect(screen["height"] as? Int == 402)
}
}
2 changes: 1 addition & 1 deletion Tools/Viewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ make viewer # or: scripts/build-viewer.sh
## API endpoints

- `GET /api/devices` — list booted simulators and connected Android devices.
- `GET /api/snapshot?deviceId=<DEVICE_ID>` — `sim-use ui --json` → `{ screen, entries, outline, capturedAt }`. `udid=` is still accepted as a deprecated alias.
- `GET /api/snapshot?deviceId=<DEVICE_ID>` — `sim-use ui --json` → `{ screen, entries, outline, capturedAt }`. `screen.orientation` carries the CLI's calibrated interface orientation (`portrait`, `landscape-right`, …) and is omitted when the CLI reports none (Android). `udid=` is still accepted as a deprecated alias.
- `POST /api/tap` — replay `sim-use tap @N` on the selected element.

## Controls
Expand Down
9 changes: 8 additions & 1 deletion Tools/Viewer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,14 @@ export default function App() {
)}
{snapshot?.screen && (
<span>
{snapshot.screen.width}×{snapshot.screen.height} ·{" "}
{snapshot.screen.width}×{snapshot.screen.height}
{/* Mirror the outline header: portrait is the default
and earns no tag, only a rotated screen shows one. */}
{snapshot.screen.orientation &&
snapshot.screen.orientation !== "portrait" && (
<> ({snapshot.screen.orientation})</>
)}{" "}
·{" "}
{matchIds
? `${matchIds.size} / ${snapshot.entries.length} match`
: `${snapshot.entries.length} elements`}
Expand Down
9 changes: 9 additions & 0 deletions Tools/Viewer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ export interface Screen {
appLabel: string;
width: number;
height: number;
/**
* Calibrated interface orientation forwarded from `describe-ui
* --json` (`data.orientation`): `"portrait"`,
* `"portrait-upside-down"`, `"landscape-right"` or
* `"landscape-left"`. Absent when the CLI didn't calibrate
* (Android, legacy daemons). Widened to `string` for
* forward-compat, like `Device.platform`.
*/
orientation?: string;
}

export interface Snapshot {
Expand Down
Loading