## Description
[Demo](https://www.loom.com/share/943140c634704c67b878b1815639aaaf)
1) Use the queued query UI for cloud mode initial query and follow-ups. Clean up old optimistic pending user query rich content machinery.
2) Properly hook setup commands for follow-up execution environment setup into the requested command-like setup command UI.
## Description
Specs for remote codebase indexing based off of
https://docs.google.com/document/d/1G4sDjVwatYMQC-BHsR3OvtlX6De27HYel7H8SSJQyM8/edit?usp=sharing
## Testing
N/A spec only
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
<!--
The entries below will be used when constructing a soft-copy of the
stable release changelog. Leave blank or remove the lines if no entry in
the stable changelog is needed. Entries should be on the same line,
without the `{{` `}}` brackets. You can use multiple lines, even of the
same type. The valid suffixes are:
* NEW-FEATURE: for new, relatively sizable features. Features listed
here will likely have docs / social media posts / marketing launches
associated with them, so use sparingly.
* IMPROVEMENT: for new functionality of existing features.
* BUG-FIX: for fixes related to known bugs or regressions.
* IMAGE: the image specified by the URL (hosted on GCP) will be added to
Dev & Preview releases. For Stable releases, see the pinned doc in the
#release Slack channel.
* OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are
shown in-app per release.
-->
CHANGELOG-NEW-FEATURE: {{text goes here...}}
CHANGELOG-IMPROVEMENT: {{text goes here...}}
CHANGELOG-BUG-FIX: {{text goes here...}}
CHANGELOG-BUG-FIX: {{more text goes here...}}
CHANGELOG-IMAGE: {{GCP-hosted URL goes here...}}
CHANGELOG-OZ: {{text goes here...}}
## Description
Fixes#9838 and fixes REMOTE-1423
Add a block-level flag for conditionally clearing output grid contents
in-place on ansi::ClearMode::All (`esc[2j`) rather than clearing by
'scrolling' + appending to block-level scrollback.
In a traditional terminal the sequence clears the entire screen - in
ghostty we see that frame-redrawing resizes for claude code, for
instance, clear the entire terminal display (not appending to
scrollback). This implements that behavior at a block-level for CLI
agent TUIs that Warp is 'aware' of.
Preserves existing behavior for other cases to limit blast radius of the
change - I think there are cases where the current block-level
clear-by-scrolling behavior might be preferable/intended
CHANGELOG-BUG-FIX: Fixes issue with repeated TUI redraws for CLI agents
on terminal pane resize.
Adds basic UI elements for cloud agent conversation continuation once
the runner is dead:
* 'continue' button in tombstone and details panel
* dedupe the optimistically-added follow-up user query from the
blocklist when follow-up session is started
## Description
Adds Chrome-style cross-window tab dragging behind the
`DragTabsToWindows` feature flag. A user can drag a tab out of a window
to create a new one, drag it into another window's tab bar to attach it,
and keep dragging through multiple attach/detach cycles without
releasing the mouse.
Product behavior is fully described in
`specs/pei/cross-window-tab-drag/PRODUCT.md`; the architectural
rationale is in `specs/pei/cross-window-tab-drag/TECH.md`.
https://www.loom.com/share/94d21b4b573c4f6893684142d66b844a
## How it works
A cross-window drag has two shapes depending on where it starts:
- **Single-tab window** — the source window itself follows the cursor
and acts as the drag preview. No second window is created.
- **Multi-tab window** — when the user drags a tab out of the tab bar, a
dedicated preview window is spun up to hold the dragged tab, and the
source window stays in place showing its remaining tabs.
As the user drags, we continuously hit-test the cursor against the tab
bars of other windows in z-order. When the cursor enters an eligible tab
bar we show a lightweight ghost (insertion slot + floating chip) in the
target; the live view tree only moves at drop time, except in the
back-to-caller case where the tab is transferred so the source window
can host real reordering. If the cursor leaves a target tab bar, any
handoff is reversed and the drag continues. On drop, the preview is
either promoted to a permanent window (no target), folded into the
target (handoff committed), or cleaned up (no-op).
## State machines
Full ASCII versions live in the module doc at
`app/src/workspace/cross_window_tab_drag.rs`. Mermaid renderings:
### Single-tab source window
```mermaid
stateDiagram-v2
[*] --> Floating: begin_single_tab_drag
Floating --> Transitioning: cursor enters target tab bar
Transitioning --> InsertedInTarget
InsertedInTarget --> Floating: cursor leaves target tab bar (reverse_handoff)
InsertedInTarget --> FinalizeHandoff: on_drop while inserted
Floating --> FinalizeFloatingWindow: on_drop while floating
FinalizeHandoff --> [*]
FinalizeFloatingWindow --> [*]
```
The source window itself is the preview, so no extra window is created.
`FinalizeFloatingWindow` just leaves the source window where the user
dropped it.
### Multi-tab source window
```mermaid
stateDiagram-v2
[*] --> Floating: begin_multi_tab_drag (creates preview window)
Floating --> GhostInTarget: cursor enters target tab bar (deferred)
GhostInTarget --> Floating: cursor leaves target tab bar
Floating --> Transitioning: cursor re-enters source (back-to-caller)
Transitioning --> InsertedInTarget
InsertedInTarget --> Floating: cursor leaves source tab bar (reverse_handoff)
InsertedInTarget --> FinalizeHandoff: on_drop while inserted
GhostInTarget --> FinalizeHandoff: on_drop over target
Floating --> FinalizePreviewAsNewWindow: on_drop while floating
FinalizeHandoff --> [*]
FinalizePreviewAsNewWindow --> [*]
```
`GhostInTarget` is a hover-only state — no view-tree transfer happens
until drop. The `InsertedInTarget` branch is reserved for the
back-to-caller path, where the preview must be kept alive so the user
can drag the tab back out again.
## Infrastructure changes
Most of the diff lands in shared infrastructure rather than in
feature-specific code. Each piece exists to satisfy a specific product
invariant:
- **Move a live tab between windows without restarting it.** A user
dragging a tab between windows expects their terminal, scrollback, agent
state, and animations to be preserved — kill-and-respawn would break the
illusion of one continuous gesture. WarpUI gains the ability to relocate
a live view tree (and its non-rendered structural children) into a
different window, which is what makes the dragged tab feel like the same
tab no matter which window is hosting it.
- **Make z-order observable so drop targeting matches what the user
sees.** When windows overlap, dropping a tab "into" an occluded window
through the window in front of it would feel buggy. The window manager
now exposes front-to-back ordering so attach targeting only considers
windows that are actually reachable from the current cursor position.
- **Show preview windows without disrupting the user's typing context.**
A preview window appearing under the cursor would steal focus from
whatever the user was typing into and would briefly flash blank before
its content is ready. A new windowing primitive lets us materialize a
window at exact bounds without taking focus, paired with a
focus-suppression hook that covers the gap before the preview's content
paints for the first time.
- **Closing a window because its tab moved should be silent.** Today,
closing a window with running processes prompts "Close window?" and
tears down panes — both correct for normal closes, both wrong when the
window is closing only because its content moved elsewhere. New
workspace flags and a dedicated termination mode let transfer-driven
closes skip the prompt and the teardown, so the user never sees a dialog
that suggests data loss during a harmless transfer. Snapshots also skip
the temporary preview workspaces so they don't leak into persistence.
- **One owner of cross-window drag state.** Multiple windows mutating
each other in response to the same drag event is exactly the shape of
bug that produces duplicated tabs and stale subscriptions. Concentrating
the drag state machine in a singleton, with workspaces only reacting to
its returned decisions, removes the re-entrancy entirely and makes "what
state is the drag in?" a single question with a single answer.
- **One drag implementation across tab presentations.** Horizontal tabs
and the vertical tabs panel are different visual surfaces, but the user
expects identical drag behavior from both. Both UIs now emit the same
drag actions and feed the same orchestration code, which keeps them from
drifting apart and prevents accidental "works for horizontal, broken for
vertical" regressions.
- **Specs and integration tests.** Product behavior and architectural
decisions are checked into `specs/pei/cross-window-tab-drag/` so future
changes have something to preserve. Integration coverage exercises
detach, attach, reattach, reverse-handoff, target-side reorder, and
drop-outside flows behind the feature flag rather than gating on a
specific OS.
Behind a feature flag, so no change for users until it's rolled out.
## Testing
- New integration tests cover detach, attach, reattach, reverse-handoff,
reorder-in-target, and drop-outside scenarios.
- Manually verified single-tab and multi-tab drags against all scenarios
in `specs/pei/cross-window-tab-drag/PRODUCT.md` § Success Criteria on
macOS.
## Server API dependencies
No server dependencies.
## Agent Mode
- [ ] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-NEW-FEATURE: You can now drag tabs out of a window into their
own window, or between windows, similar to Chrome.
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
Given the fact that we're planning on accommodating multiple variants of
cloud agents, we need to change the agent icons in the conversation
list, notifications, pane header, and vertical tabs to support different
harnesses. Peter drew up some mocks for this, and we'll use the new icon
+ status variants across all of these surfaces.
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
demo: https://www.loom.com/share/066e5842bf0541fa808925100cc6529e
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
Following the pattern for resuming claude conversations, we add support
for codex conversations.
These changes are pretty straightforward:
- Pull out `fetch_transcript_envelope` and `entries_to_jsonl` from the
claude implementation and reuse
- Write the codex transcript to disk using either the stored timestamp
on the envelope or the current time to write the directories
(`/.codex/sessions/YYYY/MM/DD/...-<session_id>.jsonl`)
## Screenshots / Videos
<!-- Attach screenshots or a short video demonstrating the change, where
appropriate. Remove this section if it is not relevant to your PR. -->
Demo: https://www.loom.com/share/fc40514af96649a9b35d3c85f2888627
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
-->
Tested locally by running a codex cloud agent, closing it, and then
using Safia's resume conversation script to trigger a followup message
in that conversation.
Also added unit tests for writing the envelope.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
Add transcript upload for codex cloud agent runs, mirroring what we
already have for claude transcripts.
Of note:
- codex nests session JSONL files within `YYYY/MM/DD` folders, we walk
the dirs here to find the session JSONL before the first snapshot
upload. This first walk shouldn't be expensive in practice—we are
running these in a context where there shouldn't be any other sessions
(cloud agent).
- We cache some metadata that we parse from the transcript on the
harness runner like the codex version and `cwd` since we don't expect
that to change over the course of the session.
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
-->
Tested by running locally and confirming that the codex transcripts do
get uploaded to GCS in the format that we expect. Also added unit tests
for parsing metadata.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Update data model to support triggering a follow-up execution on an
existing ambient agent conversation with a dead VM.
* Updates `AmbientAgentViewModel` to understand run executions
* Support spawning follow-up run execution for existing
task/conversation and connecting to new shared session
Fixes APP-4320
## Description
When an org enforces a command denylist override, the entire denylist UI
was previously disabled — users couldn't add their own entries. This PR
merges the org and user denylists into a single list where:
- **Org rows**: remove button disabled, tooltip on hover ("This option
is enforced by your organization's settings and cannot be customized."),
text in disabled color
- **User rows**: fully editable — remove button works, no tooltip
- **Editor**: always enabled when AI is on, so users can always add new
entries
- **Deduplication**: if a user entry matches an org entry, only the org
entry appears (user's copy persists in their profile)
- **Execution**: the merged list is used for command execution checks —
both org and user entries deny commands
Applies to both the legacy AI settings page and the execution profile
editor.
https://www.loom.com/share/93ff56e922724394b6c64d9511626a6a
## Linear
REMOTE-1318
## Test plan
- 4 unit tests in `permissions_test.rs`: merge behavior, deduplication,
org helper, empty org override
- Manual testing confirmed: org rows grayed out with tooltip, button not
clickable, user rows removable, editor always enabled, dedup works
- All presubmit checks pass (fmt, clippy, 5779 tests)
## Specs
- `specs/REMOTE-1318/PRODUCT.md` — 17 behavioral invariants
- `specs/REMOTE-1318/TECH.md` — implementation plan
---
[Conversation](https://staging.warp.dev/conversation/11216c5d-ac43-4de7-9ec4-ad2523b0f9c0)
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Two related fixes to the remote-server setup flow:
### 1. Gate remote-server install on a glibc preinstall check (APP-4281)
The prebuilt remote-server binary is linked against glibc 2.31. On older
Linux hosts (e.g. RHEL/Rocky/CentOS 8 with glibc 2.28) the binary
downloads fine but fails at runtime, leaving users stuck. This PR adds a
lightweight, fail-open preinstall probe that runs over the existing SSH
`ControlMaster` socket *before* any user-visible install affordance.
### 2. Don't fail the install when staging-dir cleanup races
`install_remote_server.sh` ran `trap 'rm -rf "$tmpdir"' EXIT` under `set
-e`. When `rm -rf` hit a "Directory not empty" / `EBUSY` race after the
binary had already been moved into place, the trap's non-zero exit
replaced the script's success exit, surfacing as `install script failed
(exit 1)` in the manager. The cleanup is now best-effort (`rm -rf
"$tmpdir" 2>/dev/null || true`) so post-success races no longer break
the install. Real install failures (curl, tar, missing binary,
unsupported arch/OS) still propagate normally because they happen before
the trap fires.
Fixes APP-4281
## Testing
Tested locally with an RHEL 7 docker container (which uses glibc 2.28)
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
[Conversation](https://staging.warp.dev/conversation/86cbc3ea-d9de-4b23-832a-fa8b23c0f295)
· [Tech
spec](https://staging.warp.dev/drive/notebook/oGmQYNHrHzuGx3FegfsEuQ)
<!--
CHANGELOG-IMPROVEMENT: Warp now silently falls back to a regular SSH
session on remote hosts where the prebuilt remote-server binary is
incompatible (e.g. glibc < 2.31), instead of attempting an install that
would fail at runtime.
CHANGELOG-BUG-FIX: Remote-server installs no longer fail when the
staging-directory cleanup hits a "Directory not empty" race after the
binary has already been moved into place.
-->
Co-Authored-By: Oz <oz-agent@warp.dev>
## Description
Fixes APP-4002
<img width="444" height="303" alt="Screenshot 2026-04-28 at 5 42 20 PM"
src="https://github.com/user-attachments/assets/1c45e5fa-1a20-4aa9-8666-c6d59b781fa5"
/>
This is a defensively coded UI in case something else leads to missing
file contexts.
<img width="469" height="113" alt="Screenshot 2026-04-28 at 5 40 44 PM"
src="https://github.com/user-attachments/assets/f2bd2c03-c529-49a2-8c6c-4d1efdc37544"
/>
When an LLM requests a `read_files` tool call with line ranges entirely
beyond EOF (e.g., lines 1891–2090 of a 1237-line file), the client
returns `ReadFilesResult::Success { files: [] }` — the file silently
vanishes from the result. This renders as an empty box with a green
checkmark in the blocklist UI.
**Root cause:** `TextFileAccumulator::flush_range` only emitted a
segment on final flush for whole-file reads (`final_flush &&
self.whole_file`). For ranged reads where no lines fall within the
requested range, the buffer stays empty and no segment is emitted. The
file ends up in neither `file_contexts` nor `missing_files`.
**Fix:**
1. **Primary:** Change `flush_range` to always emit a segment on final
flush (`!self.buf.is_empty() || final_flush`), so every requested range
produces a `TextFileSegment` even when entirely past EOF.
2. **Defensive:** Add rendering fallback that shows a red X error box
with "Failed to read files" when `ReadFilesResult::Success` has empty
`file_contexts`, preventing empty boxes for any future edge case.
3. **Tests:** Updated existing test and added two new tests covering
out-of-bounds ranges on non-empty files.
## Testing
- Updated `empty_file_with_ranges_produces_no_segment` →
`empty_file_with_ranges_produces_empty_segment` (expects 1 segment with
empty content)
- Added `range_past_eof_produces_empty_segment` — 5-line file, range
10..15
- Added `multiple_ranges_some_past_eof` — 5-line file, ranges [1..3,
10..15]
- All 23 text_file_reader tests pass
- `cargo fmt` and `cargo clippy` clean
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-BUG-FIX: Fixed read_files tool showing an empty box when the
LLM requests line ranges beyond the end of a file.
---
[Conversation](https://staging.warp.dev/conversation/ef9f9688-ca1e-4eb3-b29a-35c5c13e80da)
| [Plan](https://staging.warp.dev/drive/notebook/lAlU2uG6KN5y96mdmk8wYL)
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Refactors `OrchestrationEventStreamer` so v2 orchestration SSE
connections are opened only for conversations that actually need them in
the current process.
## What
A conversation now subscribes to its SSE feed iff it has both:
- a real role in an orchestration tree — child (the conversation has a
parent agent) or parent (it has at least one registered child run_id),
and
- an active local consumer — an open agent view, or an `agent_sdk`
driver in CLI / cloud worker processes.
Solo conversations and passive views of remote runs (shared-session
viewers, remote-child placeholders) no longer subscribe. The streamer is
the single owner of the consumer registry and the eligibility decision;
consumers register/unregister around their lifetime and the streamer
re-evaluates eligibility at every state change.
Other lifecycle improvements:
- The `Success`-transition start trigger and the conversation-status
tracking it relied on are gone. Status is no longer part of the
subscription decision.
- A child's run_id is pruned from any tracked parent's filter when the
child conversation is removed; the parent's SSE is reconnected with the
smaller filter or torn down if it has no remaining role.
- The SSE `run_ids` filter is recomputed from current state on each open
/ reconnect.
Tech spec: `specs/review-sse-connection-strategy/TECH.md`.
## Why
The pre-rewrite lifecycle had three problems: wrong start trigger (only
fired on `ConversationStatus::Success`), wrong stop trigger (only on
conversation removal — abandoned parents kept live SSEs), and wrong
scope (every cloud-backed conversation self-registered, including
passive viewers of remote runs).
## Testing
- Unit tests in `orchestration_event_streamer_tests.rs` cover the
consumer/role gate, restore-on-startup cursor merging, mid-flight
deletion (both Ok and Err paths), and SSE reconnection when children are
discovered after the connection is open.
- `cargo fmt`, `cargo clippy -p warp --lib --tests -- -D warnings`, and
the streamer test module all pass locally.
- Manual validation runbook (sections A–F + spot-checks) is documented
in TECH.md.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
CHANGELOG-IMPROVEMENT: Tighten orchestration event subscription scope so
SSE runs only for active parent and child agent runs.
Co-Authored-By: Oz <oz-agent@warp.dev>
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
[APP-3805](https://linear.app/warpdotdev/issue/APP-3805/client-server-version-skew)
— handle client/server version skew for the SSH remote-server binary.
Previously the remote binary lived at a single unversioned path. When a
client updated but the remote still had an older binary, the two could
silently go out of sync.
This PR does three things:
1. **Version the installed path.** The binary is now written to
`{dir}/{binary_name}-{version}`, so any client-server drift becomes a
path miss and triggers a reinstall. The unversioned path is kept for
`cargo run` / `deploy_remote_server` dev loops.
2. **Check versions on handshake.** `initialize()` now compares
`server_version` against the client's release tag. On mismatch, the
manager deletes the stale binary, tears the session down, and emits
`SessionConnectionFailed` so the failed-banner path fires.
3. **Auto-update without a prompt.** When `check_binary()` misses but
the remote already has an install directory, we skip the "Install Warp
SSH tools?" modal and install directly with `is_update: true`. The
shimmer reads "Updating Warp SSH Extension..." instead of
"Installing...". Dev clients without a release tag fall through to the
normal prompt so they don't accidentally CDN-install over a
locally-deployed binary.
## Testing
- `cargo test -p remote_server`, `cargo clippy -D warnings`, `cargo fmt`
— all clean.
- Manual against `alokedesai@136.107.29.130`:
- Fresh install: modal → "Installing Warp SSH Extension..." → Ready.
- Reconnect with a newer client tag: handshake mismatch detected, stale
binary removed, reconnect reinstalls.
- Reconnect with an older client tag while a newer versioned binary is
on the remote: auto-update, no modal, "Updating..." shimmer.
- Forced install failure on the update path: failed banner renders.
## Server API dependencies
None — warp-server already supports `?version=` on `/download/cli`
(#10284).
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
<!-- Please remember to add your design buddy onto the PR for review, if
it contains any UI changes! -->
This PR adds a /continue-locally slash command to serve as another
entrypoint for continuing a cloud conversation locally (does the same
thing as clicking the continue locally button in the tombstone or info
panel).
## Testing
<!--
How did you test this change? What automated tests did you add? If you
didn't add any new tests, what's your justification for not adding any?
If you're not sure whether you should add a test, check our testing
policy:
https://www.notion.so/warpdev/How-We-Code-at-Warp-257fe43d556e4b3c8dfd42f70004cc72#1f97825450504baa9c5fd87a737daa09
-->
demo: https://www.loom.com/share/fb393e595c0b4aa9805cdaeedaa6fd06
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
## Changelog Entries for Stable
<!--
The entries below will be used when constructing a soft-copy of the
stable release changelog. Leave blank or remove the lines if no entry in
the stable changelog is needed. Entries should be on the same line,
without the `{{` `}}` brackets. You can use multiple lines, even of the
same type. The valid suffixes are:
* NEW-FEATURE: for new, relatively sizable features. Features listed
here will likely have docs / social media posts / marketing launches
associated with them, so use sparingly.
* IMPROVEMENT: for new functionality of existing features.
* BUG-FIX: for fixes related to known bugs or regressions.
* IMAGE: the image specified by the URL (hosted on GCP) will be added to
Dev & Preview releases. For Stable releases, see the pinned doc in the
#release Slack channel.
* OZ: Oz-related updates. Use `CHANGELOG-OZ`. At most 4 Oz updates are
shown in-app per release.
-->
CHANGELOG-IMPROVEMENT: Added a `/continue-locally` slash command to
continue cloud conversations locally.
## Description
Add feature flag and scaffolding for cloud->cloud handoff, incl bindings for follow-up API and abstracting formerly-task-specific public API on AmbientAgentViewModel into getters backed by now-execution-specific data.
## Description
Adds support for swapping out the viewer-side shared session piping for an existing TerminalView/Manager to support continuing cloud agent conversations across VM lifecycle boundary.
Adds `SessionSharingInitialLoadMode` for ignoring replay events when joining a shared session for a cloud agent task with agent scrollback.
## Description
This change updates the Git dialogs to compare against the correct
parent branch instead of the previous broken detect_parent_branch
Specifically, this PR:
- Introduces `detect_fork_point` to determine the point where the
current branch diverged from its parent.
- Uses the fork point when no parent branch is specified, ensuring
accurate diffs even when the parent branch is not explicitly set.
Fixes
[WAR-7378](https://linear.app/warpdotdev/issue/WAR-7378/fix-publish-and-pr-on-diverged-parent-branch-bug)
## Testing
Tested manually by verifying that diffs and commit message generation
now correctly use the fork point rather than main when working on
stacked branches.
## Server API dependencies
N/A
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>
## Description
Refactor AmbientAgentViewModel to remove NotAmbientAgent state and simplify semantics - presence of the model indicates that the parent view is rendering an ambient agent task.
## Description
Restore orchestration event delivery on the client after a Warp restart
so that a parent conversation continues to receive lifecycle events and
inbox messages from its children — including terminal events that
arrived while Warp was not running.
See the full design in `specs/replay-agent-events-on-restore/PRODUCT.md`
and `specs/replay-agent-events-on-restore/TECH.md`.
This is a re-land of warpdotdev/warp-internal#24999, which was reverted
in warpdotdev/warp-internal#25055 due to a CI race. This version fixes
the test compilation issue (missing fields in `AmbientAgentTask` struct
literal in `conversation_ended_tombstone_view_tests.rs`).
### What
- Persists the per-conversation event cursor across restarts.
- Adds `last_event_sequence: Option<i64>` to `AgentConversationData`
(SQLite) and `AIConversation`.
- New `BlocklistAIHistoryModel::update_event_sequence` helper writes the
cursor through `write_updated_conversation_state` after each event
batch.
- Also persists the cursor to the server (fire-and-forget) so driver /
cloud restarts can resume without local SQLite state.
- Restores `OrchestrationEventPoller.watched_run_ids` and re-establishes
event delivery on `BlocklistAIHistoryEvent::RestoredConversations`.
- New `on_restored_conversations` handler issues `GET
/agent/runs/{run_id}` for each restored parent and uses the response
inline `children` and `last_event_sequence` to populate watched run ids
and merge the cursor (`max(SQLite, server)`).
- Fetch failures retry with exponential backoff (1s, 2s, 5s, 10s capped)
keyed off a per-conversation `restore_fetch_failures` counter; reset on
success and on conversation removal.
- Gated on `OrchestrationV2`. Shared-session viewers and conversations
without children are skipped.
- `Success` parents resume delivery immediately; `InProgress` parents
defer to the existing `on_conversation_status_updated` path.
- Restores V1 lifecycle subscriptions on restart by extending the
existing `RestoredConversations` handler in `OrchestrationEventService`
to re-register `lifecycle_subscription_routes` for restored child
conversations whose parents are present locally.
### Why
After a Warp restart, parent conversations were silently receiving no
further events from children. The `event_cursor` in
`OrchestrationEventPoller` was always initialized to 0, so even if
delivery had resumed, every event since the start of the conversation
would have replayed and produced duplicate messages. V1 lifecycle
subscription routes were also not restored, so V1 parents missed child
status transitions.
## Testing
- Added unit tests in
`app/src/ai/blocklist/orchestration_event_poller_tests.rs` covering:
cursor merge from server vs SQLite, retry on `get_ambient_agent_task`
failure, V2 gating, shared-session-viewer exclusion, cleanup on delete,
and `last_event_sequence` round-trip through
`AIConversation::new_restored`.
- Added unit test coverage in
`app/src/ai/blocklist/orchestration_events_tests.rs` for V1 lifecycle
re-registration on restore.
- Manual verification per
`specs/replay-agent-events-on-restore/TECH.md`.
## Server API dependencies
- [x] Does this change rely on a [new server
API](https://www.notion.so/warpdev/How-to-add-a-new-full-stack-feature-8412cede405a4ec194b32bdd4b951035?pvs=4#04da1e6a493542d68b3e998c7d339640)?
- [x] If so, is the use of this API restricted to client channels that
rely on the staging server (e.g. WarpDev)?
The companion server change adds:
- `last_event_sequence` on `Task` (`ai_tasks` column), surfaced inline
on `GET /agent/runs/:run_id`.
- `PATCH /agent/runs/:run_id/event-sequence` for client cursor writes.
- `children` inline on the `GET /agent/runs/:run_id` response.
## Agent Mode
- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode
Co-Authored-By: Oz <oz-agent@warp.dev>
---------
Co-authored-by: Oz <oz-agent@warp.dev>