feat: typed command results, batch 3 (clipboard, appstate) — Phase 2#937
Merged
Conversation
Wire two more commands into the CommandResultMap spine as closed shapes,
grounded in the handlers' literal returns:
- clipboard (src/core/dispatch.ts handleClipboardCommand) -> a discriminated
union on `action`: read => { text }, write => { textLength, message }.
- appstate (src/daemon/handlers/session-state.ts handleAppStateCommand) -> a
discriminated union on `platform`: Apple (ios/macos) session state — now
including the iOS-only device_udid / ios_simulator_device_set locators the
previous hand-written mirror OMITTED — or Android package/activity.
Both result types move from the open client-types.ts mirror (DaemonResponseData
& {…}) into new src/contracts/{clipboard,app-state}.ts and are wired through
CommandResult<'clipboard'> / CommandResult<'appstate'>. Public export names are
preserved (re-exported via client-types.ts -> index.ts), so no API break.
Tightening clipboard to a closed union surfaced an unguarded .text/.textLength
access in an Android integration test (previously masked by the Record index
signature); fixed with discriminant guards. The parity test now pins all 12
migrated commands; the public-root export test gains clipboard/appstate samples.
Verified: tsc --noEmit, oxfmt + oxlint --deny-warnings, fallow audit clean,
Layering Guard empty, 791 tests across core/contracts/client/commands pass.
Size Report
Startup median (7 runs, lower is better):
Top changed chunks: no changes in the largest emitted chunks. |
Member
Author
|
Reviewed current head 71a2f3c. I checked the #913/#934 typed-results context, the diff, the clipboard and appstate handler return literals, and the command routing traits. No actionable blockers found: public export names are preserved, clipboard is correctly modeled as a read/write discriminated union, appstate matches the Apple-session vs Android-state handler branches including iOS locators, and all 21 checks are green. Marking ready-for-human. |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 2 (typed results) batch 3: wire
clipboardandappstateinto theCommandResultMapspine as closed discriminated unions, grounded in the handlers' literal returns. Continues #913/#934.clipboardsrc/core/dispatch.tshandleClipboardCommandaction:read→{ text },write→{ textLength, message }appstatesrc/daemon/handlers/session-state.tshandleAppStateCommandplatform: Apple (ios/macos) session state, or Android{ package, activity }Notable: handler-grounding caught a gap
The previous hand-written
AppStateCommandResultmirror omitted the iOS-onlydevice_udid/ios_simulator_device_setlocators that the handler actually returns. The new closed contract includes them — a strictly more accurate public type.Mechanics (same template as batches 1-2)
src/contracts/clipboard.tsandsrc/contracts/app-state.ts(moved out of the openclient-types.tsmirror, dropping theDaemonResponseDataindex signature).CommandResultMapgainsclipboard/appstate; client methods returnCommandResult<'name'>.ClipboardCommandResult,AppStateCommandResultre-exported viaclient-types.ts→index.ts) — no API break.Tighter type surfaced a latent test bug
Closing
clipboardto a discriminated union exposed an unguarded.text/.textLengthaccess in an Android integration test (previously masked by theRecordindex signature). Fixed with discriminant guards — exactly the kind of unsafe access the migration is meant to eliminate.Verification
tsc --noEmitexit 0oxfmt+oxlint --deny-warningscleanfallow audit --base origin/maincleanvitestcore/contracts/client/commands → 104 files / 791 tests passRemaining for Phase 2
keyboard(platform×action union — needs the Android keyboard-state types) is the next typed-results batch;wait/alertare genuinely open (wait also has an internal name-collision; alert's iOS path returns a generic Record) and will becomeCommandRequestResultin the mirror-cleanup PR. Then (b) theTypedErrorgraft and (c) deleting the remainingclient-types.tsresult mirror.