mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
Remove in-app SDK (#43)
* chore: delete internal/agent package
* chore(build): remove sdk-android from gradle settings
* chore(makefile): remove sdk-android targets
* chore(ci): remove release-android job from release workflow
* chore(folio): remove sdk-android dependency
* chore(folio): remove SDK initialization from FolioApplication
* chore(folio): delete snapshot extractor files
* feat(folio): add balance to account card content description
* feat(folio): add hierarchy content descriptions to LedgerScreen
* refactor(folio): rewrite spec.ts to use ax extractors
* docs: remove in-app SDK from README
* feat(folio): add focused_input indicator to App
* docs: remove in-app SDK from index
* refactor(runner): remove agent SDK connection and snapshot step
* test(runner): update tests for SDK removal
* docs: remove Android SDK section from getting-started
* refactor(testrun): remove agent SDK connection setup
* docs: remove snapshots from writing-specs
* docs: remove in-app SDK from architecture doc
* docs(folio): update README for SDK removal
* docs: update per-step cycle diagram in architecture doc
* fix(folio): detect screens from unique element presence, not id: selectors
testTag() in Compose is not exposed as resource-id without testTagsAsResourceId.
Use desc: selectors for elements unique to each screen instead of id: path queries.
* feat(folio): add screen root contentDescription for scoped ax selection
Each screen root gets semantics { contentDescription = "ScreenName" } so
sanderling specs can scope element lookups through the screen: desc:LoginScreen > desc:login_submit.
* fix(folio): scope all ax selectors through screen root nodes
Use desc:ScreenName > desc:element path queries so every selector is
rooted at the screen level. focusedInput stays unscoped since it lives
in the app root, outside any screen.
* fix(folio): guard newAccountBalanceIsZero against navigation false positives
Scoped selectors return [] when not on HomeScreen so accounts vanish and
reappear as apparently-new on each visit. Skip the check when prev was empty.
* chore(folio): link @sanderling/spec to local pkg/spec for IDE type checking
* feat(spec): add desc, class, clickable, enabled, checked, focused, selected to AccessibilityElement
Runtime fields set by the verifier were missing from the TypeScript type,
causing linting errors on el.desc and related accesses in specs.
* chore(folio): switch to bun, add tsconfig.json for IDE type checking
- Remove package-lock.json, add bun.lock
- Add tsconfig.json so VSCode resolves @sanderling/spec types
- Fix parseAccount/parseLedgerRow to accept string | undefined
This commit is contained in:
60 files changed
+298
-3354
No files matched your search
@@ -15,15 +15,12 @@ flowchart TB
|
||||
end
|
||||
|
||||
SC["Maestro sidecar (JVM)"]
|
||||
SDK["in-app SDK\n(Device / Emulator)"]
|
||||
CH["Chrome (CDP)"]
|
||||
RD[("runs/")]
|
||||
IN["sanderling inspect\nHTTP + SSE"]
|
||||
UI["Web UI (React)"]
|
||||
|
||||
D -->|gRPC| SC
|
||||
SC -->|UIAutomator / XCTest| SDK
|
||||
R -->|"Unix socket<br/>(pause / state / logs)"| SDK
|
||||
D -->|CDP| CH
|
||||
|
||||
T --> RD --> IN --> UI
|
||||
@@ -35,16 +32,13 @@ flowchart TB
|
||||
|
||||
**Maestro sidecar (JVM).** A Kotlin process that wraps `maestro-client` and exposes a gRPC surface matching the `DeviceDriver` interface. Handles UI input, screenshots, the system accessibility tree, and OS-level alerts. Native platforms only.
|
||||
|
||||
**In-app SDK.** A Kotlin (or Swift for iOS) library linked into the app under test. Exposes a Unix socket to the runner. Provides pause and resume, view-hierarchy dumps, coverage reads, log capture, and user-registered state extractors. Native platforms only.
|
||||
|
||||
**Chrome (CDP).** For web targets, the Go binary drives Chrome directly over the Chrome DevTools Protocol. No sidecar or in-app SDK is involved.
|
||||
**Chrome (CDP).** For web targets, the Go binary drives Chrome directly over the Chrome DevTools Protocol. No sidecar is involved.
|
||||
|
||||
## Transports
|
||||
|
||||
| Channel | Platform | Transport | Purpose |
|
||||
|---|---|---|---|
|
||||
| Go to Maestro sidecar | Native | gRPC (localhost TCP) | UI input, screenshots, system alerts |
|
||||
| Go to in-app SDK | Native | Unix domain socket | Pause / resume, hierarchy, coverage, logs, extractors |
|
||||
| Go to Chrome | Web | Chrome DevTools Protocol | UI input, screenshots, DOM hierarchy, console logs |
|
||||
|
||||
On native, the transport split exists because only real UI events need to cross process and OS-API boundaries. Introspection is cheap, frequent, and lives on a fast local socket directly to the app. On web, CDP handles both.
|
||||
@@ -58,23 +52,21 @@ On native, the transport split exists because only real UI events need to cross
|
||||
The heart of the system is:
|
||||
|
||||
```
|
||||
pause ─► capture state ─► evaluate properties ─► pick action ─► resume ─► dispatch
|
||||
fetch state ─► evaluate properties ─► pick action ─► dispatch
|
||||
```
|
||||
|
||||
**Native (Android / iOS):**
|
||||
|
||||
1. The runner asks the driver to wait until the UI is idle.
|
||||
2. The runner sends `PAUSE` to the SDK over the Unix socket. The SDK freezes the main runloop at a safe point.
|
||||
3. The SDK sends back a `STATE` message: view hierarchy, coverage delta, logs since last step, exception list, snapshot values.
|
||||
4. The runner feeds state into goja. Extractors re-read; properties re-evaluate; the action generator returns a weighted tree.
|
||||
5. The runner writes the trace entry for this step.
|
||||
6. The runner picks an action by weight.
|
||||
7. The runner sends `RESUME` to the SDK, then dispatches the action through the driver (gRPC to sidecar → Maestro → UIAutomator or XCTest).
|
||||
8. Loop.
|
||||
2. The runner fetches the UI hierarchy and logs from the sidecar.
|
||||
3. The runner feeds state into goja. Extractors re-read; properties re-evaluate; the action generator returns a weighted tree.
|
||||
4. The runner writes the trace entry for this step.
|
||||
5. The runner picks an action by weight and dispatches it through the driver (gRPC to sidecar -> Maestro -> UIAutomator or XCTest).
|
||||
6. Loop.
|
||||
|
||||
**Web (Chrome):**
|
||||
|
||||
Steps 2-3 use CDP to capture the DOM hierarchy and console logs directly; there is no SDK pause/resume. The rest of the cycle is identical.
|
||||
CDP captures the DOM hierarchy and console logs directly. The rest of the cycle is identical.
|
||||
|
||||
The cycle runs hundreds of times per minute. Every step produces one row in `trace.jsonl` and one screenshot.
|
||||
|
||||
Reference in new issue
Block a user