feat: typed command results, batch 1 (Phase 2 typed-results)#913
Conversation
Wire the dormant CommandResultMap spine into the public client return types for three commands whose daemon handlers return clean, closed result objects: - boot -> BootCommandResult (src/daemon/handlers/session-state.ts) - shutdown -> ShutdownCommandResult (src/daemon/handlers/session-state.ts) - viewport -> ViewportCommandResult (src/core/dispatch.ts handleViewportCommand) Each result type mirrors the handler's literal return exactly; the public client methods narrow from the generic Record (CommandRequestResult) to these precise shapes. No field removed; shapes that the runtime leaves open stay open.
Size Report
Startup median (7 runs, lower is better):
Top changed chunks: no changes in the largest emitted chunks. |
|
Reviewed + verified the types against the real handler returns — accurate, and a purely type-level change (no runtime risk).
Because this only annotates |
|
I found one public-surface gap before this merges: the root package export still does not expose the result names that this PR introduces/uses.
Please add the relevant type exports to the root public surface before merge. I would include at least the three concrete result types, and probably |
|
Phase 2 typed-results — batch 1
Activates the dormant
CommandResultMapspine (src/core/command-descriptor/command-result.ts) for the first time in the public client return surface. Three commands whose daemon handlers return a clean, closed result object are narrowed from the genericRecord(CommandRequestResult = DaemonResponseData = Record<string, unknown>) to a precise shape, keyed by their registry literal name and wired throughCommandResult<Name>.Every typed field below was confirmed against a re-read of the handler's literal
return(accuracy gate). No field the runtime produces is omitted; no field the runtime doesn't set is invented.Commands typed
bootBootCommandResultdevices.boot:Promise<CommandRequestResult>→Promise<CommandResult<'boot'>>src/daemon/handlers/session-state.ts:244-254shutdownShutdownCommandResultdevices.shutdown:Promise<CommandRequestResult>→Promise<CommandResult<'shutdown'>>src/daemon/handlers/session-state.ts:309-318viewportViewportCommandResultcommand.viewport:Promise<CommandRequestResult & { width; height }>(open) →Promise<CommandResult<'viewport'>>(closed)src/core/dispatch.ts:347-361(handleViewportCommand)Exact shapes
boot/shutdownhandlers return a single fixed object literal (no spread) on their onlyok: truepath;finalizeDaemonResponseonly appendsartifactswhen apath/artifact field exists, which these never produce, so the data reaches the client unchanged.viewportreturns{ width, height, ...successText(...) }fromhandleViewportCommand; it is dispatched via the generic path and — having noandroidBlockingDialogGuard— never gets awarningappended, so the wire shape stays closed.Why only these three (skipped, with reasons)
press/fill/longpress— already seeded inCommandResultMap, but the contract types describe the in-process dispatch result, NOT the wire response. The daemon builds the response viabuildTouchVisualizationResult(src/daemon/handlers/interaction-touch.ts), which dynamically spreadsbackendResult, reference-frame fields andsuccessText. Wiring those into the client would lie, so they stay in the map but are not wired this batch.screenshot/snapshot/devices/apps/install/open/close/ leases / materializations — already returned as precise normalized types by the client (notRecord); nothing to narrow.appState/keyboard/clipboard/wait/alert/back/home/rotate— already have hand-authored (intentionally open) result types.reactNative/prepare/ interactions / gestures /perf/logs/network/record/trace/settings/diff— handlers spread dynamic/Recorddata or platform-specific results; not cleanly closed.Semver
MINOR / public-SDK type-safety improvement. Public client return types narrow from
Recordto precise shapes. No exported name removed (ViewportCommandResultrelocated tosrc/contracts/viewport.tsand re-exported;BootCommandResult/ShutdownCommandResultadded). No runtime behavior change. Open shapes were kept open; only genuinely closed handler returns were closed.Further batches follow as more handlers are confirmed to have closed return shapes.
Verification
tsc -p tsconfig.json --noEmit→ exit 0oxfmt --write+oxlint --deny-warnings(changed files) → exit 0vitest run client core/command-descriptor contracts→ 223 passed; plus management/dispatch/daemon-handlers (614) andsrc/__tests__public/export suites (329) → all passgit grep "from '.*commands/'" src/daemon src/platforms) → empty