Skip to content

Conversation

@ThomasK33
Copy link
Member

Adds mobile parity for task tools and bash live output.

  • Mobile: render task tool cards (task/task_await/task_list/task_terminate/agent_report) with “Open workspace” navigation.
  • Mobile: stream bash-output events into bash tool cards via transient buffer (avoids timeline spam; keeps tail when final output is missing).
  • Desktop: task tool IDs can open the spawned workspace (fallback: copy ID).
  • Shared: compute/init durationMs; fix session timing interval typing.
  • Mobile: hydrate/persist workspace aiSettings (model + thinking, incl xhigh).

tests:

  • make typecheck-react-native
  • make static-check

đź“‹ Implementation Plan

React Native app catch-up (mobile/) — post-rebase fixes + task + live bash output parity

Status (as of 2025-12-23)

âś… Completed in this worktree:

  • RN typechecks fixed (make typecheck-react-native).
  • Task tool cards + “open task workspace” affordance (mobile + desktop).
  • Live bash output streamed into the bash tool card (no timeline spam).
  • Workspace AI settings parity on mobile:
    • hydrate from backend workspace.getInfo().aiSettings
    • support xhigh thinking level
    • best-effort persist via workspace.updateAISettings
  • make typecheck + make static-check passing.

Goals

  • Restore make typecheck-react-native to passing on latest origin/main.
  • Add task tool UI parity on mobile (task, task_await, task_list, task_terminate, agent_report).
  • Add Open task workspace affordance:
    • Mobile: navigate to /workspace/<taskId>.
    • Desktop/Web: navigate/select the workspace for <taskId>.
  • Investigate remaining parity gaps between mobile and desktop/web (features intentionally missing vs. backlog candidates).
  • Add live bash output parity on mobile (stream bash-output into the bash tool card, without timeline spam).

Parity audit (desktop/web vs mobile): additional gaps to consider

A) Chat input / composer UX

  • Voice input (desktop has VoiceInputButton; mobile has none). Est: M (~+300–600 LoC)
    • Desktop: src/browser/components/ChatInput/VoiceInputButton.tsx
  • Image attachments (desktop supports paste/drag/drop + preview; mobile has none). Est: M (~+300–700 LoC)
    • Desktop: src/browser/components/ImageAttachments.tsx
  • Queued message UI (desktop shows queued message with send-now/edit controls; mobile doesn’t). Est: M (~+200–400 LoC)
    • Desktop: src/browser/components/Messages/QueuedMessage.tsx
  • Inline model + thinking controls (desktop uses inline selector + thinking slider; mobile primarily uses a modal sheet). Est: S/M (~+150–400 LoC)
    • Desktop: src/browser/components/ModelSelector.tsx, src/browser/components/ThinkingSlider.tsx
  • Slash command suggestions richness (desktop shows descriptions/arg hints; mobile suggestions are basic). Est: S (~+80–150 LoC)
    • Desktop: src/browser/components/CommandSuggestions.tsx

B) Streaming + usage + compaction

  • Streaming barrier richness (desktop shows phase + keybind hint + TPS; mobile tracks tokens/TPS but doesn’t render most of it). Est: S/M (~+80–200 LoC)
    • Desktop: src/browser/components/Messages/ChatBarrier/StreamingBarrier.tsx
    • Mobile: mobile/src/screens/WorkspaceScreen.tsx (token/tps tracking)
  • Usage tracking + context meter (desktop uses usage-delta + session-usage-delta; mobile ignores these events). Est: M/L (~+300–900 LoC)
    • Desktop: src/browser/stores/WorkspaceStore.ts
    • Mobile ignore list: mobile/src/messages/normalizeChatEvent.ts
  • Auto-compaction prompts (desktop responds to idle-compaction-needed; mobile ignores). Est: M (~+150–300 LoC)

C) Workspace header / metadata

  • Runtime badge (desktop shows Local/SSH/Worktree context). Est: M (~+150–300 LoC)
    • Desktop: src/browser/components/RuntimeBadge.tsx
  • Git status + branch selector (desktop header shows clean/dirty + branch controls; mobile lacks). Est: M/L (~+300–700 LoC)
    • Desktop: src/browser/components/GitStatusIndicator.tsx, src/browser/components/BranchSelector.tsx
  • MCP/project tool config UI (desktop has rich MCP modal; mobile has none). Est: L (~+600–1200 LoC)
    • Desktop: src/browser/components/WorkspaceMCPModal.tsx
  • Platform-limited: “open terminal / open editor” header buttons (desktop-only in Electron).

D) Projects/workspace management

  • Archive/unarchive + archived workspaces screen (desktop has dedicated archived view + bulk ops; mobile currently hides archived). Est: L (~+500–900 LoC)
    • Desktop: src/browser/components/ArchivedWorkspaces.tsx
    • Mobile: mobile/src/screens/ProjectsScreen.tsx
  • Workspace nesting / parent-child visualization (desktop indents child workspaces). Est: M/L (~+250–700 LoC)
    • Desktop: src/browser/utils/ui/workspaceFiltering.ts (depth map)
  • Project ordering / reordering (desktop supports project ordering controls; mobile is fixed). Est: M (~+200–500 LoC)
    • Desktop: src/browser/components/ProjectSidebar.tsx
  • Workspace cost badges / aggregation (desktop surfaces cost/usage in more places; mobile is more limited). Est: S/M (~+150–400 LoC)
    • Desktop: src/browser/components/ArchivedWorkspaces.tsx
  • Force-delete dirty workspaces (desktop has a force-delete path; mobile typically doesn’t). Est: S (~+50–120 LoC)
  • Fork workspace UI (desktop supports via commands/UI; mobile lacks). Est: M (~+150–350 LoC)

E) Settings / configuration

  • Provider configuration UI (desktop has full providers settings + SSE updates; mobile relies on slash commands / no UI). Est: L (~+600–1200 LoC)
    • Desktop: src/browser/components/Settings/sections/ProvidersSection.tsx
  • Custom model management (desktop allows add/remove/hide custom models; mobile is fixed to known models). Est: L (~+500–1000 LoC)
    • Desktop: src/browser/components/Settings/sections/ModelsSection.tsx
  • Experiments toggles (desktop has experiments UI; mobile has none). Est: M (~+250–500 LoC)
    • Desktop: src/browser/components/Settings/sections/ExperimentsSection.tsx

F) Tool card rendering

  • Missing specialized renderer for code_execution (desktop has dedicated UI; mobile falls back to generic). Est: S/M (~+100–250 LoC)
    • Desktop: src/browser/components/tools/CodeExecutionToolCall.tsx
    • Mobile: mobile/src/messages/tools/toolRenderers.tsx

Suggested follow-up scopes (pick one)

  1. Small wins: TPS display + code_execution tool card parity (net ~+150–300 LoC)
  2. Chat/composer parity: images + queued messages + voice (net ~+600–1400 LoC)
  3. Workspace mgmt parity: archive view + nesting + fork (net ~+700–1400 LoC)
  4. Settings parity: providers + models (+ maybe experiments) (net ~+1000–2500 LoC)

Completed implementation (reference): green typecheck + task open-workspace + live bash output (net ~+450–600 LoC product code)

1) Fix the 3 TypeScript errors

1.1 workspace-init now requires durationMs

Update the shared init-state plumbing so mobile can populate the new field.

  • src/browser/utils/messages/ChatEventProcessor.ts
    • Extend InitState with durationMs: number | null.
    • Preserve the start timestamp (init-start) instead of overwriting it on init-end.
    • Compute durationMs = endTimestamp - startTimestamp on init-end.
  • mobile/src/messages/normalizeChatEvent.ts
    • In emitInitMessage(), include durationMs: initState.durationMs.

1.2 Fix sessionTimingService timer typing

  • src/node/services/sessionTimingService.ts
    • Change the tick-interval map type to be platform-agnostic:
      • from Map<string, NodeJS.Timeout>
      • to Map<string, ReturnType<typeof setInterval>>

1.3 Add the new bash-output stream event to mobile’s exhaustive handler map

Even though we’ll handle bash-output as transient state (see §3), mobile still needs a handler for schema exhaustiveness.

  • mobile/src/messages/normalizeChatEvent.ts
    • Add:
      • "bash-output": () => []

2) Task tool UI parity + “Open workspace” (mobile + desktop)

Key fact: taskId == workspaceId (verified via src/node/services/taskService.ts).

Desktop reference:

  • Routing: src/browser/components/Messages/ToolMessage.tsx
  • UI: src/browser/components/tools/TaskToolCall.tsx

2.1 Mobile: render task tool cards + open workspace

  • mobile/src/messages/tools/toolRenderers.tsx
    • Add renderSpecializedToolCard cases for:
      • task
      • task_await
      • task_list
      • task_terminate
      • agent_report
    • Follow existing mobile patterns:
      • isXToolArgs(...) type guards
      • coerceXToolResult(...) coercers
      • buildXViewModel(...) returning ToolCardViewModel

UI requirements:

  • task

    • Expanded:
      • prompt (mono/CodeBlock)
      • report (Markdown) when available
      • “Open workspace” button that does router.push(/workspace/${taskId}).
  • task_await

    • Per-task result row includes “Open” action for each taskId.
  • task_list

    • Each listed task row includes “Open” action.
  • task_terminate

    • Each terminated task row includes “Open” action (useful for post-mortem).
Defensive UX
  • If taskId is missing or malformed, hide the button.
  • If navigation fails (route missing), show a toast with the ID so the user can copy it.

2.2 Desktop/Web: add “Open workspace” affordance in task tool UI

  • src/browser/components/tools/TaskToolCall.tsx
    • Update the TaskId rendering (or call-sites) to add an Open workspace link/button.
    • Use useWorkspaceContext():
      • look up metadata in workspaceMetadata by taskId
      • call setSelectedWorkspace(...) to select/navigate.

Design constraints:

  • Only show an enabled Open control when workspaceMetadata.get(taskId) exists.
  • Otherwise, fall back to copy-to-clipboard of the ID (so the user can search).

3) Live bash output parity on mobile (stream event bash-output)

Desktop already supports this via:

  • src/browser/stores/WorkspaceStore.ts transient state liveBashOutput
  • src/browser/components/tools/BashToolCall.tsx + useBashToolLiveOutput(...)
  • src/browser/utils/messages/liveBashOutputBuffer.ts (appendLiveBashOutputChunk)
  • src/common/constants/toolLimits.ts (BASH_TRUNCATE_MAX_TOTAL_BYTES)

3.1 Intercept bash-output events outside the timeline

  • mobile/src/screens/WorkspaceScreen.tsx
    • In handlePayload, detect payload.type === "bash-output":
      • append the chunk to a transient store keyed by toolCallId
      • return early so we do not update timeline state for high-frequency chunks.

Also clear output when the bash tool finishes:

  • Clear on tool-call-end for the bash tool (or when we observe a completed tool message with a final output).

3.2 Implement a transient store + hook for mobile bash output

  • Add a BashOutputContext (or extend WorkspaceChatContext) that provides:
    • appendChunk({ toolCallId, text, isError })
    • getLiveOutput(toolCallId) → { combined, stdout, stderr, truncated } | undefined
    • clear(toolCallId)

Reuse existing, platform-agnostic helpers:

  • appendLiveBashOutputChunk + toLiveBashOutputView from src/browser/utils/messages/liveBashOutputBuffer.ts
  • BASH_TRUNCATE_MAX_TOTAL_BYTES from src/common/constants/toolLimits.ts
RN compatibility note (TextEncoder)

liveBashOutputBuffer.ts uses TextEncoder to measure UTF-8 bytes. If Hermes lacks TextEncoder in our RN runtime, add a small fallback (best-effort) or a polyfill. Prefer a defensive runtime check with a clear error message in dev builds.

3.3 Render live output in the existing mobile bash tool card

  • mobile/src/messages/tools/toolRenderers.tsx
    • Extend the bash tool renderer so that while status === "executing":
      • show liveOutput.combined in a scrollable code block
      • show a “truncated” badge if liveOutput.truncated === true
    • Once completed, prefer the final result.output (existing behavior).

4) Validation

  • make typecheck-react-native
  • make typecheck

Optional low-effort tests (only if they’re easy/pure):

  • src/browser/utils/messages/ChatEventProcessor.test.ts: durationMs calculation.
  • src/browser/utils/messages/liveBashOutputBuffer.test.ts: truncation + interleaving logic.

Generated with mux • Model: openai:gpt-5.2 • Thinking: xhigh

Change-Id: I8ea68bf1a85193d443d4febb4b297ccc7da783e0
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I6c6ec0ded4beb2a3ebb4b83b34a2442198173b43
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33 ThomasK33 added this pull request to the merge queue Dec 23, 2025
Merged via the queue into main with commit 6cbe539 Dec 23, 2025
20 checks passed
@ThomasK33 ThomasK33 deleted the mobile-app-touch-ups branch December 23, 2025 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant