147 lines
8.2 KiB
Markdown
147 lines
8.2 KiB
Markdown
# APP-3858: Tech Spec — Remote Control Entrypoint
|
|
|
|
## Problem
|
|
The CLI agent footer's "Share session" button opens the share modal, which is an unnecessary step for the primary use case (quick mobile handoff). We need to make it a one-click action that starts sharing without scrollback, auto-copies the link, and shows a stop button while active.
|
|
|
|
## Relevant Code
|
|
- `crates/warp_core/src/ui/icons.rs (10-296)` — `Icon` enum; needs `Phone01` variant
|
|
- `app/assets/bundled/svg/phone-01.svg` — phone icon for start-state (on branch)
|
|
- `Icon::StopFilled` — existing icon reused for stop-state
|
|
- `app/src/search/slash_command_menu/static_commands/commands.rs` — slash command definitions
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs (491-500)` — `share_session_button` creation
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs (1104-1108)` — CLI toolbar `ShareSession` render
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs (1636-1644)` — agent view toolbar `ShareSession` render
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs (1893, 2025-2027)` — `AgentInputFooterAction::ShareSession` handler
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs (2037-2045)` — `AgentInputFooterEvent` enum
|
|
- `app/src/ai/blocklist/agent_view/agent_input_footer/toolbar_item.rs (48, 74, 88)` — `AgentToolbarItemKind::ShareSession` display label and icon
|
|
- `app/src/terminal/view/use_agent_footer/mod.rs (217-218, 851-852)` — event forwarding
|
|
- `app/src/terminal/view/use_agent_footer/mod.rs (1019-1041)` — `UseAgentToolbarEvent` enum
|
|
- `app/src/terminal/view/shared_session/view_impl.rs (415-472)` — `attempt_to_share_session` (scrollback guard at 436-448)
|
|
- `app/src/terminal/view/shared_session/view_impl.rs (476-520)` — `on_session_share_started` (auto-opens sharing dialog at 515)
|
|
- `app/src/terminal/view/shared_session/view_impl.rs (522-529)` — `stop_sharing_session`
|
|
- `app/src/terminal/view/shared_session/view_impl.rs (1288-1311)` — `copy_shared_session_link`
|
|
- `app/src/terminal/shared_session/mod.rs (39)` — `COPY_LINK_TEXT` constant
|
|
- `app/src/terminal/shared_session/mod.rs (267-290)` — `SharedSessionActionSource` enum
|
|
|
|
## Current State
|
|
|
|
**Button**: A single static `share_session_button` with `Icon::Share`, tooltip "Share session". Click dispatches `AgentInputFooterAction::ShareSession` → emits `AgentInputFooterEvent::OpenShareSessionModal`.
|
|
|
|
**Event flow**: `OpenShareSessionModal` bubbles through `UseAgentToolbarEvent::OpenShareSessionModal` → `TerminalView::open_share_session_modal` → opens the sharing dialog.
|
|
|
|
**Post-share**: `on_session_share_started` unconditionally auto-opens the sharing dialog so the user can copy the link.
|
|
|
|
**No stop affordance**: The button never changes. Stopping requires the pane header overflow menu.
|
|
|
|
## Proposed Changes
|
|
|
|
### 1. Add icon variant
|
|
In `crates/warp_core/src/ui/icons.rs`, add one variant:
|
|
- `Phone01` → `"bundled/svg/phone-01.svg"`
|
|
|
|
The stop state reuses the existing `Icon::StopFilled`.
|
|
|
|
### 2. Two buttons instead of one
|
|
Replace the single `share_session_button` field in `AgentInputFooter` with two fields:
|
|
|
|
**`start_remote_control_button`**: `Phone01` icon, label "/remote-control". On click dispatches `AgentInputFooterAction::StartRemoteControl`.
|
|
|
|
**`stop_remote_control_button`**: `StopFilled` icon, label "Stop sharing". On click dispatches `AgentInputFooterAction::StopRemoteControl`.
|
|
|
|
### 3. Split action and event enums
|
|
**`AgentInputFooterAction`** (mod.rs:1893): Replace `ShareSession` with:
|
|
- `StartRemoteControl`
|
|
- `StopRemoteControl`
|
|
|
|
**`AgentInputFooterEvent`** (mod.rs:2037): Replace `OpenShareSessionModal` with:
|
|
- `StartRemoteControl`
|
|
- `StopRemoteControl`
|
|
|
|
**`UseAgentToolbarEvent`** (use_agent_footer/mod.rs:1019): Replace `OpenShareSessionModal` with:
|
|
- `StartRemoteControl`
|
|
- `StopRemoteControl`
|
|
|
|
Each action handler is trivial — it just emits the corresponding event up the chain.
|
|
|
|
### 4. Swap buttons at render time
|
|
In `render_cli_toolbar_item` and `render_toolbar_item` for the `ShareSession` variant, instead of always rendering the start button, check `terminal_model.lock().shared_session_status()`:
|
|
- Not sharing → render `start_remote_control_button`
|
|
- `is_active_sharer()` or `is_share_pending()` → render `stop_remote_control_button`
|
|
|
|
The footer already re-renders on `CLIAgentSessionsModel` changes. We need to verify shared session status changes also trigger re-renders; if not, subscribe to the relevant model event.
|
|
|
|
### 5. Handle `StartRemoteControl` in `TerminalView`
|
|
In `handle_use_agent_footer_event` (use_agent_footer/mod.rs:217):
|
|
- Call `attempt_to_share_session(SharedSessionScrollbackType::None, Some(FooterChip), SessionSourceType::Terminal, ctx)` with a new `bypass_conversation_guard: bool` parameter set to `true`.
|
|
|
|
**Bypass the scrollback guard**: Add `bypass_conversation_guard: bool` to `attempt_to_share_session` (view_impl.rs:415). When `true`, skip the guard at lines 436-448. All existing callers pass `false`.
|
|
|
|
### 6. Auto-copy link on share start
|
|
Thread `source: Option<SharedSessionActionSource>` through the share-started flow:
|
|
- `Event::StartSharingCurrentSession` gains a `source` field
|
|
- Terminal manager forwards it to `on_session_share_started`
|
|
|
|
In `on_session_share_started` (view_impl.rs:476):
|
|
- When source is `FooterChip`: skip `toggle_sharing_dialog`, call `copy_shared_session_link`, show toast "Remote control link copied".
|
|
- All other sources: keep existing behavior (auto-open sharing dialog).
|
|
|
|
### 7. Handle `StopRemoteControl` in `TerminalView`
|
|
Call `self.stop_sharing_session(SharedSessionActionSource::FooterChip, ctx)`.
|
|
|
|
### 8. Update toolbar item metadata
|
|
In `toolbar_item.rs`:
|
|
- Display label: `"Share Session"` → `"/remote-control"`
|
|
- Icon: `Icon::Share` → `Icon::Phone01`
|
|
|
|
### 9. Add `/remote-control` slash command
|
|
Add a `REMOTE_CONTROL` static command in `commands.rs` with:
|
|
- name: `/remote-control`
|
|
- description: "Start remote control for this session"
|
|
- icon_path: `"bundled/svg/phone-01.svg"`
|
|
- availability: CLI agent sessions only
|
|
|
|
Register it in the command list. Handle it in the slash command dispatch to emit the same `StartRemoteControl` action as the chip.
|
|
|
|
### 10. Banner copy
|
|
When sharing is started from the remote control entrypoint (`SharedSessionActionSource::FooterChip`), the inline banners show:
|
|
- "Remote control active" (instead of "Sharing started")
|
|
- "Remote control stopped" (instead of "Sharing ended")
|
|
|
|
This is threaded via an `is_remote_control: bool` field on `SharedSessionBanners::ActiveShare` and `LastShared`.
|
|
|
|
## End-to-End Flow
|
|
```
|
|
Start:
|
|
click start_remote_control_button
|
|
→ AgentInputFooterAction::StartRemoteControl
|
|
→ AgentInputFooterEvent::StartRemoteControl
|
|
→ UseAgentToolbarEvent::StartRemoteControl
|
|
→ attempt_to_share_session(None, FooterChip, bypass=true)
|
|
→ terminal manager establishes connection
|
|
→ on_session_share_started(source=FooterChip)
|
|
→ skips sharing dialog, copies link, shows toast
|
|
→ footer re-renders: swaps to stop_remote_control_button
|
|
|
|
Stop:
|
|
click stop_remote_control_button
|
|
→ AgentInputFooterAction::StopRemoteControl
|
|
→ AgentInputFooterEvent::StopRemoteControl
|
|
→ UseAgentToolbarEvent::StopRemoteControl
|
|
→ stop_sharing_session(FooterChip)
|
|
→ footer re-renders: swaps back to start_remote_control_button
|
|
```
|
|
|
|
## Risks and Mitigations
|
|
- **Scrollback guard bypass**: Deliberately allowing no-scrollback shares for remote control. Guard still applies for all other entry points (share modal, context menu, etc.).
|
|
- **State sync**: Reading `shared_session_status()` at render time means the button reflects state changes from any entry point. Must verify shared session status changes trigger footer re-renders.
|
|
- **Threading source through share-started flow**: `Event::StartSharingCurrentSession` and the terminal manager callback need to carry the source. Keep it optional so existing callers are unaffected.
|
|
|
|
## Testing and Validation
|
|
- Existing shared session tests pass (protocol unchanged).
|
|
- Manual: start CLI agent → click "Remote control" → verify link copied + toast → button shows stop state → click stop → session ends + button reverts.
|
|
- Verify starting share from pane menu causes footer to show stop button.
|
|
|
|
## Follow-ups
|
|
- "Text link to my device" stretch goal.
|
|
- Rename agent view (non-CLI) share button if desired.
|