refactor(runtime): let platform runtimes list apps and read app state directly - #2295
Conversation
… directly The root host carried two adapters, appInventory and appState, that only forwarded a platform call back into that platform's own package. Each platform runtime now performs its own listApps and appState call through a lazy import inside its package, keeping the deferred load, the AbortSignal threading, and the package/bundleId -> id rename. PlatformRuntimeHost loses both keys, so Android, Apple and Harmony fixtures no longer stub the two platforms they do not own. Android is the one platform runtime whose package now reaches adb directly. The adb host that adb mechanics require is bound by a module side effect that only the root can perform, so the Android runtime-module registration binds it before the module loads. loadAndroidMechanics keeps its own binding import for the root host ports that reach mechanics without binding a runtime; neither binder subsumes the other. Android appstate now runs one foreground-focus loop instead of two. The host shaped readAndroidAppState/AndroidAppStateHost pair is gone: limrun's adapter already closes over its own adb executor, so it calls the executor variant directly, and that variant took the per-attempt abort check the host variant had. AppStateRuntimeCommand and AppStateRuntimeCommandResult described the deleted host port and go with it. Tests: the new ordering test in src/platform-runtime-android-adb-binding.test.ts was seen red by deleting the binding import from that registration (order came back ["android-runtime", "adb-host"]); the composed-gateway listApps test in the same file was seen red by reverting the Android runtime's inlined listApps to a host.appInventory lookup (TypeError reading 'android'); the new abort test in packages/platform-android/src/app-state.test.ts was seen red by removing both signal?.throwIfAborted() calls from readAndroidFocusWithExecutor (the second dumpsys was issued and the call resolved). All green after.
The two PLATFORM_RUNTIME_HOST_FILES rows point at host files this change deletes, and the ./platform-runtime-app-state-host.ts composition allowance has no importer left.
Size Report
Startup median (7 runs, lower is better):
|
|
Reviewed exact head |
…host binding
The Android runtime now calls adb from inside its package for listApps and
appState, which needs the process-wide adb host port bound. That dependency
was hidden in a registry wrapper doing a side-effect import, with a paragraph
explaining why it and loadAndroidMechanics did not subsume each other and an
import-order test pinning the ordering. The package now declares the
dependency: createAndroidRuntimeModule({ bindAdbHost }) awaits the binding
before the runtime loads, and the composition root supplies the one binding
implementation (evaluating its adb host module). The wrapper, the paragraph
and the import-order test are gone; the routed listApps test stays and a
routed appState test joins it.
|
Addressed in 6df2d93. The Android runtime module is now constructed with its adb dependency declared in the package's own interface: |
* origin/main: perf: bundle runtime dependencies and report full install size (#2310) ci: avoid unrelated Apple runner cache invalidation (#2303) fix(web): preserve the backend ref so snapshot refs match actionable refs (#2283) test(daemon): session-open-url-prewarm through the request seam (#2304) test(daemon): session-devices-batch-runtime through the request seam (#2305) chore(gates): layering baselines ratchet against merge-base (#2299) test(daemon): one typed conformance helper for the daemon runtime suites (#2298) chore(layering): derive the contracts export inventory from package.json (#2297) perf: bundle tar-stream to reduce install footprint (#2286) docs: simplify agent context and resolve conflicting guidance (#2287) refactor(cli): let help resolve command aliases itself and retire R12 (#2293) refactor(commands): retire the navigation-only type projection (#2294) feat(runtime): route managed leases through contained transports (#2285) refactor(contracts): build unavailable runtime facts once (#2291) refactor(cli): derive the common flag readers from the common-field table (#2292) feat(daemon): add managed allocation operation journal (#2284)
|
refactor(runtime): let platform runtimes list apps and read app state directly
Summary
Two root host adapters,
appInventoryandappState, only forwarded a platform call back intothe platform's own package. Before:
appsandappstateleft the Apple, Android or Harmonyruntime and crossed into root to reach their own package. After: each runtime makes that
listApps/appStatecall through a lazyimport()inside its package, keeping the deferredload, the abort threading and the
package/bundleId->idrename.PlatformRuntimeHostlosesboth keys, so fixtures stop stubbing platforms they do not own. Android
appstatecollapses to oneforeground-focus loop, now shared with limrun.
The Android runtime's new in-package adb calls need the process-wide adb host port bound. The
package declares that dependency instead of hiding it:
createAndroidRuntimeModule({ bindAdbHost })awaits the binding before the runtime loads, and the composition root supplies the one binding
implementation (evaluating
src/platform-runtime-android-adb-host.ts, which binds once). Noregistry wrapper, no caller-must-import-first ordering; the binding stays lazy, so the
composition root's eager closure is unchanged.
33 files touched, all inside the runtime/platform boundary.
Validation
Head
6df2d93627(typed Android adb-host dependency on top of558560ab7b):src/platform-runtime-android-adb-binding.test.ts(routedlistAppsandappStatethrough the composed gateway) andpackages/platform-android/src/runtime-facade.test.ts(binding awaited before load; a failing binding keeps the runtime unloaded) green;vitest relatedon the touched modules 221 files / 1402 tests green;oxlint,oxfmt,tsc(root andpackages/platform-android),check:layering,check:fallow --base origin/mainand the eager-closure budget gate clean.Tested commit: 558560a — pnpm check:affected --run green locally (format, lint, typecheck, layering, di-seams, fallow, mcp-metadata, build, package, integration-node, macos-coverage, vitest-related, integration-progress, replay-compat, daemon-wire-compat, affected-selector, gate-manifest, gate-manifest-model, depgraph, tmpdir-leaks, tmpdir-leaks-model, coverage-model, wire-compat-model, production-exports, bundle-owner-files, fixture-cache, fixture-fallback, command-docs, agent-guidance, xctest-selection, maestro-conformance, mutation-model)
On a booted iPhone 17 Pro simulator and
emulator-5554, these printed byte-identicaloutput before and after: