Repository navigation
v4.2.0 — Agent-UX polish: sticky clientId, full React hook coverage, regex everywhere
Highlights
Eleven commits worth of agent-UX improvements landed since v4.1.0. Theme: tighten the surface, give agents better hooks (literally and figuratively), close small inconsistencies.
Bridge — sticky clientId across reconnects
A WebSocket drop used to leak the clientId — nextClientId('ios') would increment and the reconnecting app would land on ios-2, ios-3, … every time Fast Refresh bounced the socket.
Now: on close the ClientEntry moves into a 10-minute ghost map keyed by (platform, deviceId, bundleId). A reconnecting client matching all three reuses the same id. Covers Fast Refresh reloads, app-backgrounded coffee breaks, Xcode rebuilds, brief network blips. Pure server-side behaviour change — wire protocol unchanged.
React hook coverage — all 18 stable hooks + use
HOOK_KIND in the babel plugin now maps every stable React 16 / 18 / 19 hook to a dedicated kind:
| React 19 | React 18 | React 16.8 |
|---|---|---|
| Optimistic, ActionState, Use | SyncExternalStore, DeferredValue, Id, InsertionEffect, Transition | State, Reducer, Memo, Callback, Ref, Effect, LayoutEffect, ImperativeHandle, Context, DebugValue |
use(promise | context) is the one stable hook whose name doesn't match the classic /^use[A-Z]/ detector. Now caught via a widened /^use([A-Z]|$)/ plus a React-namespace guard (/^_?[Rr]eact\d*$/) on the <obj>.use(...) form, so calls like database.use(middleware) / app.use(router) don't show up as false-positive hooks. countHookSlots regex picks up bare use( with a negative lookbehind to skip method calls. End-to-end verified on a 21vek React 19.2 app — _useProbe (kind: Use) aligned correctly with the fiber slot, no drift in surrounding hooks.
react-dom-only hooks (useFormStatus, useFormState) are intentionally NOT mapped — this is a React Native library.
Call-site mcpId on every hook entry
Each __mcp_hooks metadata entry now stamps an mcpId in the same shape JSX elements use for data-mcp-id:
{
"kind": "State", "name": "count", "hook": "useState",
"mcpId": "count:hooks/useCart:42"
}Drop the value straight into Read("hooks/useCart.ts", 42) to jump to the call site without grepping. select.hooks.mcpIds filter takes the same /regex/flags syntax as names for targeting a single call.
Regex in step criteria
fiber_tree__query step criteria (name / mcpId / testID / text) now accept exact strings AND /pattern/flags slash form — one consistent regex syntax wherever string matching shows up:
steps: [{ name: "/^Pressable/" }] // Pressable / PressableView / ...
steps: [{ mcpId: "/:screens\\/HomeScreen\\/.*:/" }] // anything from one folder
steps: [{ text: "/error|warning/i" }]Malformed regex falls back to exact / substring comparison so a typo doesn't silently mismatch everything.
Projection knobs — more agent control, less guessing
previewCap default bumped 100 → 250 (more useful string previews land before collapsing to ${str} markers); now agent-tunable per call alongside the existing path / depth / maxBytes. New tunable knobs: objectCap (default 30, wide objects truncate above) and arrayCap (default 50). All five share a common makeProjectionSchema so every projection-using tool (console, network, errors, log_box, navigation, reactQuery, storage, fiber_tree, metro events) gets them automatically.
Path syntax extended to strings — errors[-1].stack[0:500] slices the last 500 chars verbatim. Path-ending-in-slice bypasses previewCap since slicing is an explicit truncation request; other paths landing on a string still respect the cap.
JSON Schema keywords (default:, minimum:, maximum:, enum:, minLength:, minItems:, properties: + required:, format:, examples:) applied across every inputSchema. Constraints that used to live only in description prose ("Default 280, clamped 64..1568") are now machine-readable for agents and describe_tool.
Five quick wins
host__screenshot: every response carrieshash;{ unchanged: true, lastMeta }returns the previously-shipped meta so polling loops don't need a re-query.host__list_devices({ connected: true })filters to just devices with a live MCP client attached.metro__symbolicate: stack parser strips leading<ErrorName>: <message>header lines and accepts Hermes anonymous variants (bare@file:L:C,anonymous@…, packager-rooted?anon_N_/abs/path).- console module: intercepts
trace/group/groupCollapsed/groupEndon top of the classic five (traceauto-captures stacks). Defensive patching when the RN console doesn't natively implement a method. - Stamping
hashon screenshot meta and exposingobjectCap/arrayCapknobs from the projection.
Wire protocol
Unchanged. PROTOCOL_VERSION stays at 2. Clients on v4.1 keep talking to a v4.2 server and vice versa.
Full diff: v4.1.0...v4.2.0