* Remove test assertions redundant with TypeScript static analysis
Drop assertions that merely verify unset optional properties are
undefined (a JavaScript language guarantee) and a second test block
whose only runtime value was re-checking literals just assigned to
typed variables. TypeScript's compiler already validates that these
object literals conform to the declared union types.
* fix: remove unused descriptor variable to fix noUnusedLocals
* refactor: extract shared test utilities from duplicated patterns
Introduce src/__tests__/test-utils/ with reusable device fixtures,
session factories, store factory, snapshot builders, and mocked
binary helpers. Migrate 27 test files to use these shared utilities,
eliminating duplicated DeviceInfo constants, makeSession/makeStore
helpers, snapshot node builders, and withMockedAdb/withMockedXcrun
across core, daemon, and handler tests.
Add AGENTS.md guidance to check test-utils before writing new tests.
* fix: restore public Metro type contract coverage with satisfies fixtures
* refactor: reduce duplication and simplify codebase
Eliminate copy-pasted functions, inline error boilerplate, and repeated
patterns across daemon handlers and platform modules.
Key changes:
- Deduplicate isEnvTruthy, displayNodeLabel, roundPercent into single sources
- Extract throwDaemonError helper for client/CLI daemon response errors
- Add sessionNotFoundResponse/unsupportedOperationResponse helpers and
adopt errorResponse() across ~30 handler files (-565 lines)
- Unify BATCH_PARENT_FLAG_KEYS/REPLAY_PARENT_FLAG_KEYS into shared
mergeParentFlags helper in handler-utils
- Extract createLinuxToolResolver for screenshot/clipboard tool detection
- Remove stale type-sync comments from contracts.ts and metro.ts
* refactor: deeper structural simplification pass
Bigger wins from restructuring, not just mechanical dedup:
- cli.ts: move logTailStopper to try/finally (eliminates 28 duplicate
calls), extract writeCommandCliOutput/writeLogsCliOutput/writeNetworkCliOutput
from 350-line if/else chain, fix remaining throwDaemonError site
- session-store.ts: replace 67-line sanitizeFlags destructure/reconstruct
with 10-line pick-from-array loop
- record-trace: extract finalizeRecordingOverlay helper, replacing 4
copies of the telemetry+overlay block across ios/android/recording files
- Deduplicate normalizeText (finders.ts + selectors-match.ts)
- Fix isEnvTruthy to preserve whitespace-tolerant parsing (.trim())
* fix: ensure logTailStopper runs before process.exit
process.exit() does not unwind the stack, so finally blocks are
skipped. Restore explicit logTailStopper() calls before each
process.exit() to prevent leaking the background daemon log tail
process. The finally block remains as a safety net for normal
return paths.
Also refactor writeCommandCliOutput to return an exit code instead
of calling process.exit() directly, keeping the exit decision in
the caller where cleanup is visible.
* refactor: simplify daemon failure responses
* refactor: remove redundant daemon response cast
* feat: expose bridge-facing contract and metro APIs
* chore: address review feedback on public contract exports
* refactor: reuse public daemon contracts internally
* refactor: reuse public metro types internally
* fix: widen bridge-facing public contracts
* refactor: expose metro and remote config node apis
* refactor: tighten public node api surface
* refactor: tighten metro public type boundaries
* refactor: normalize remote config public profile
* refactor: make remote config parser library-owned
* refactor: share remote config parsing primitives
* refactor: avoid regex in base url normalization
* fix: auto-manage metro companion for remote runs
* fix: fail fast on non-retryable metro bridge errors
* fix: scope metro companion ownership by profile
* fix: align remote close metro companion cleanup
* fix: guard metro companion shutdown reconnect
* test: ignore expected bridge reset in metro reconnect test
* chore: format, cleanup