Skip to content

Terminal command_result schema rejects agent's own success fields (cols/rows/written/started/resized/stopped) #3167

Description

@ToddHebebrand

Reported by semotech in #bugs (Discord, message 1534314425312608407).

Report (PII-redacted):

Follow-up to "macOS Remote Desktop permission stuck Missing — Desktop unavailable" (agent 0.103.0).

  1. Healthy: MBP M4 Max, 15.7.8 arm64 — FDA/SR/A11y/RD all Granted; Desktop Ready After User Login. loginwindow helper disabled; agent.sock srw-rw-rw-; user_session helper as console Admin.
  2. Broken same OS: MBA M1, 15.7.8 arm64 — FDA/SR/A11y Granted; RD Missing; Desktop Unavailable; Helper Not Connected (offline at check).
  3. Older: MBA Intel, 12.7.6 amd64 — FDA/SR Granted; A11y Missing; RD Unknown; Desktop Unavailable.
  4. Prior: 2019 iMac, 14.7.2 amd64 — RD Missing + loginwindow SR popup loop; sock 660 root:admin blocked user helper until chmod 666.

DB: healthy = remoteDesktop:true + user_session; broken = helper_not_connected (RD false despite other grants) or missing_permission (FDA/A11y false — often shared local account). Not OS-only (15.7.8 in both). API drops malformed term-command_result keys (written/cols/rows) — garbled remote terminal.

Need guidance: how RD TCC is granted/detected; why Helper Not Connected when SR+A11y+FDA Granted; intended sock perms Admin vs Standard; whether disabling loginwindow helper is supported.

Filed automatically by @breeze-discord triage. Verify and add labels/repro as needed.

Triage analysis

The poster's follow-up flagged a specific claim: the API drops malformed term-command_result payloads over keys like written/cols/rows. I traced this and it's real, though the causal link to visible garbling is only partially confirmed.

agentWs.ts defines terminalCommandResultSchema with result: z.object({event, sessionId, exitCode}).strict().optional() (agentWs.ts:2885-2896). Any extra key on result fails validation. But the agent's own terminal command handlers (agent/internal/remote/tools/terminal.go) never send an event field at all — StartTerminal returns {sessionId, cols, rows, started}, WriteTerminal returns {sessionId, written}, ResizeTerminal returns {sessionId, cols, rows, resized}, StopTerminal returns {sessionId, stopped}. None of these can ever pass the strict schema, so every successful terminal_start/data/resize/stop command_result the agent sends is dropped by the API as 'malformed' (agentWs.ts:2260-2270) and the corresponding ack (agentWs.ts:2513-2517) is never sent back.

Downstream impact is narrower than the poster implied: nothing else in agentWs.ts consumes a successful term- result (only the failed branch at 2279 is wired up), and actual terminal output is streamed via a separate terminal_output message type, not this ack — so this schema mismatch is log noise plus a permanently-broken ack, not the direct cause of the previously-diagnosed paste-reordering corruption. It's still a genuine, reproducible schema/implementation mismatch worth fixing on its own.

Affected code

  • apps/api/src/routes/agentWs.ts:2885-2896 — terminalCommandResultSchema.result is .strict() and only allows event/sessionId/exitCode
  • apps/api/src/routes/agentWs.ts:2260-2270 — safeParse failure path: drops the command_result and logs 'Dropping malformed term-command_result' without further processing
  • apps/api/src/routes/agentWs.ts:2513-2517 — ack is only sent after the fast-path schema parse succeeds — never reached for these payloads
  • agent/internal/remote/tools/terminal.go:61-66 — StartTerminal result: sessionId/cols/rows/started — no 'event' key, fails the API's strict schema
  • agent/internal/remote/tools/terminal.go:91-94 — WriteTerminal result: sessionId/written — same mismatch
  • agent/internal/remote/tools/terminal.go:115-120 — ResizeTerminal result: sessionId/cols/rows/resized — same mismatch
  • agent/internal/remote/tools/terminal.go:136-139 — StopTerminal result: sessionId/stopped — same mismatch

Potential fix

Widen terminalCommandResultSchema.result to accept the fields the agent actually sends (started, resized, stopped as booleans; written as number; cols/rows as numbers), matching how desktopCommandResultSchema already accepts its agent's fields (e.g. stopped), rather than using .strict() with only event/sessionId/exitCode.

Triage analysis, affected code, and fix sketch above were produced by automated investigation (@breeze-discord). Verify before relying on them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions