Aller au contenu

Desktop client adapters

Status: source-implemented client platform-adapter candidate; Desktop node-status, terminal, Workspace, and ephemeral Realtime token adapters are not release-qualified.

This directory owns reviewed host/native adapters for platform-neutral Maia client ports. The explicit .web.ts and .web.tsx port projections in src/platform select them through this folder's index.ts; features and native-mobile projections do not import this boundary. node-status.ts composes the browser-safe public SDK with the dedicated Tauri node_status command and caps requests at 2 KiB and responses at 128 KiB. The renderer still supplies only the SDK-generated envelope: the native adapter validates the ordinary Node API v1 descriptor, adds its bearer, and sends the read over fixed authenticated numeric-loopback HTTP. terminal.ts composes the public SDK with the Tauri node_request and node_cancel commands; it is the one Desktop SDK transport for every reviewed Node operation. workspace.ts reuses that exact bounded SDK transport for Workspace context show/select; it adds no native command. voice.ts invokes voice_realtime_token, validates the returned bounded short-lived setup through client-core, and exposes SDK-backed Workspace context, voice orchestrator, and Pi relay services on SingleSessionPlatform. All Node requests reuse node_request and node_cancel without a renderer bearer credential. Consequential and destructive requests wait for the native confirmation sheet; a decline maps to cancelled and an unavailable sheet to saturated, with the native reason (confirmation_declined, confirmation_unavailable) kept as the error cause. Nothing is sent in either case. This transport grants no mutation authority; sessionAvailability remains unavailable, so final relay dispatch stays disabled while Maia Node omits its external Pi adapter.

observation.ts adapts the native observation_subscribe relay to the SDK's stream relay, and the SDK's watchNodeChanges does the rest: it builds the subscribe message without a credential, validates every relayed frame with the protocol schema and its correlation id, turns committed events and snapshots into NodeChanges signals, and resumes from the last cursor after a terminal frame or a relay loss. An invalid frame, a refused subscription or a Node that restarted (epoch_changed) fails the watch, so watchers resubscribe; the cockpit reads the Node instance again before it does. Frames are change signals, never UI patches or resource data.

interaction.ts adds the mounted record-only question candidate through client-core and the same public SDK transport. Its native projection admits only interaction.list, interaction.show, and interaction.respond, with exact bounded parameters; creation and cancellation remain CLI operations. The client checks the visible Project/Session before sending an answer. Scoped requests stop on target closure, while route-owned bounded memory retains uncertain original answers and command IDs across target/drawer remounts for explicit retry. It does not persist that client memory across application restarts or retry automatically. Answers never authorize operations or activate Sessions. Mounted/native/human qualification is still pending; source presence is not acceptance.

The renderer adapter does not discover profiles, read connection descriptors, expose long-lived credentials to JavaScript, supervise the node, or become another backend. Rust owns descriptor and Gateway credential discovery and authenticated native I/O. All local-node HTTP is native-only, proxy-free, redirect-denying, deadline-bounded, and restricted to the descriptor's exact 127.0.0.1 port and fixed operation path. Before an allowed terminal request, native code verifies a fresh authenticated status identity and rechecks descriptor plus credential; the renderer remains an SDK client and receives only a correlated protocol response. The terminal adapter caps each encoded request at 512 KiB, supplies a five-second native deadline, forwards cancellation with a per-request opaque ID, preserves native outcome_unknown even after its AbortSignal becomes aborted, removes abort listeners through an Effect-owned release, and fails closed when Tauri is absent. The voice adapter maps native errors to a small Maia-owned vocabulary and never returns raw native detail. Neither adapter logs request envelopes, terminal content, tokens, or credentials.

dictation/ adapts the dictation_start, dictation_finish and dictation_cancel commands into client-core's DictationEngine: one Effect stream per session over a Tauri Channel. Every event is validated against a closed schema (malformed or oversized events fail the stream); closing the stream before its final or error event cancels the native session. Dictation reaches no Node and receives text and a level, never audio. Outside the Desktop host the engine reports engine_unavailable.

microphone-permission.ts owns the microphone_permission command used by the web voice-input projection before browser capture. It returns only authorized, denied, unavailable, or not_required outside the Desktop host, and imports the Tauri API on first use.

The native allowlist is the set of protocol feature descriptors with desktop: "reviewed-renderer-local-node", plus the exact node.status read and one token-minting command; see the Desktop README. managed-session.ts reuses the public SDK and existing native transport for bounded managed-history reads. It obtains the current Node Workspace context, queries its focus Project, filters other Workspaces, checks exact show identity, and rechecks context before returning. States are preserved without inferring turn readiness or external Pi relay eligibility. This adapter is not yet mounted in the voice UI; no authoritative picker or production fixture replacement is claimed. All other Session methods and every turn method remain denied. Maia Node remains the sole relay authority and fails final dispatch closed until the external adapter is explicitly composed and qualified. Windows, observer attach or resync, controller renew, restart, delete, reconcile and device capabilities are unsupported; Node supervision belongs to the native node_lifecycle_* commands, not to this adapter. Outside the reviewed Desktop host, both Realtime token issuance and Workspace scope access fail closed.

Run focused verification with Node 24.22.1:

pnpm --filter @maiaos/client exec node --test "src/platform/desktop/**/*.test.ts"
pnpm --filter @maiaos/client lint
pnpm --filter @maiaos/client typecheck
pnpm --filter @maiaos/client test
pnpm --filter @maiaos/client build

The real boundary is additionally checked by @maiaos/desktop native tests and headless WebKit compatibility evidence. See Architecture, Desktop and mobile clients, and client documentation.

Imported from Maia OS docs at a2175bb