The daemon accepts connections only after its configured plugins have
started, and PluginService.start started them one at a time, so each
plugin's build and process launch added to daemon startup. Configured
plugins now start together. Their providers and usage sources are still
published in config order: a plugin that finishes early waits for the
plugins listed before it, so when two plugins claim the same provider or
usage-source ID, the one listed first keeps it, as before. A failing
plugin still fails on its own.
Fixes#7979
* fix(server): retry a connected host that failed the capability check
Every failure in a connected host's acceptance step was terminal: the
row went to "error" with no retry, and the status listener ignored
later reconnects. A host rejected with unsupported_capability stayed
unusable after it was updated, until the registration was saved again
or the managing daemon restarted. Capability and other non-identity
acceptance failures now go "offline" with nextRetryAt and retry with
capped backoff (1.5 s doubling to 30 s), so an updated host comes
online by itself. Self, duplicate, changed-identity and authentication
failures stay terminal.
Fixes#7971
* fix(server): keep a retried host's relay security floor and update guidance
A scheduled capability retry built a new transport factory, which
dropped the relay security floor learned from a protected handshake, so
the retry could negotiate legacy encryption and send credentials.
Retries now reuse the registration's transport factory (createHostClient
accepts one). The update guidance also stays visible while a retry
connects, the backoff resets after a successful acceptance, and
disabling or removing a host cancels its pending retry.
* fix(pi): open an archived Pi agent's history after its folder is removed
Opening an archived agent's timeline resumes its provider for history.
Pi's resumeSession never received the resume purpose, so it launched the
Pi RPC process, and its MCP support probe, in the agent's stored working
directory. When that folder had been removed, for example with a merged
worktree, Node failed the spawn with "spawn <command> ENOENT" and the
history could not be read.
Starting the process elsewhere is not enough: with --session, Pi checks
the cwd stored in the session file's header and, outside interactive
mode, exits when that folder is missing. A history resume whose stored
folder is no longer a directory now starts Pi from the home directory on
a temporary copy of the session file whose header names that directory.
The copy streams everything after the header unchanged and is deleted
when the session closes. The agent keeps reporting its stored folder and
original session file, and the original file is not written to.
The directory check moves out of the ACP provider, which already starts
history loads from the home directory (#6228), into a shared helper both
providers use.
Fixes#7969
* test(terminal): keep the argv test child alive through its assertion
The POSIX argv test reads the terminal screen while its child can exit and dispose the parser. Keep the child alive until the assertion completes, as other screen tests do, and let the existing session cleanup terminate it.
Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>
---------
Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): close the upstream connection when a proxied client leaves
The service proxy piped the service's response to the client but never
destroyed the upstream request when the client went away. The upstream
socket stayed open and unread, so a Server-Sent Events service kept
writing into it and grew in memory. The proxy now destroys the upstream
request when the client response closes before it finished, without
logging that deliberate abort as an unreachable upstream, and a
WebSocket upgrade closes the service socket when the client socket
closes.
Fixes#8149
* test(server): publish terminal activity fixture atomically
File existence did not mean the child had finished writing its JSON. Publish the completed fixture by rename so a concurrent reader cannot parse an empty file.
Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>
* test(server): keep rollback listener ports distinct
Selecting both free ports before binding either lets the OS return the same port twice. Hold the intentionally occupied main port before selecting the standalone port so the rollback probe cannot reach the wrong server.
---------
Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(terminal): render emoji at their intended width
The native grid scales glyphs to the columns assigned by the terminal buffer. Use grapheme widths across current hosts and clients so emoji fit their slots and replay preserves cursor positions.
* fix(terminal): make width regression test portable
* test(terminal): wait for replay fixture output to finish
A trailing newline could arrive after the readiness marker and change the retained history between replay captures.
SendMessage resumes a finished Claude subagent under its original task_id
but a new tool_use_id, and the child's frames still name the original Task
call as their parent. In the same process the live source already maps the
new tool id onto the original row. After the session reopens, the child is
only known from its transcript, so the resume was declared as a new
subagent keyed by the SendMessage id: a second row, and every child frame
dropped as undeclared. That row never showed the model or the child's
reply.
Replay now hands the live source each restored child's task id, id and
presentation. The first task_started for that task id adopts the restored
row, so the resume takes the same path it takes without a reopen.
Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): forward a created agent's current state, not its pre-prompt copy
create_agent_request forwarded the snapshot createAgent returned when
registration finished, after the initial prompt had already published
the agent as running. Subscribers received that idle copy last, with an
older updatedAt, and providers that report nothing until the turn ends
left the agent listed as idle for the whole turn.
Forward the agent manager's current state instead.
Closes#8022
* test(server): drain agent persistence before fixture cleanup
---------
Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): report a Codex thread only once Codex can resume it
Codex writes a new thread's rollout at its first turn, but the adapter
starts a thread when the agent is created and reported its ID at once.
AgentManager stored that ID as the persistence handle, so a Codex agent
that was reopened before its first prompt (idle runtime release, daemon
restart, plugin tool reload) failed every prompt with "no rollout found".
The adapter now reports a thread's ID, as runtime info and as a handle,
only once it is resumable: after Codex announces the thread's first
turn, or when the thread was resumed or forked. Until then a reopened
agent starts a new session, as an unprompted Claude agent does.
Document that a persistence handle must be resumable.
* test(server): reopen promptless Codex agents without model requests
Exercise the real app-server before any first turn, so publishing an unsaved persistence handle fails at the actual resume operation.
Co-authored-by: Jeong-Uk,Kim <dnrtoki@gmail.com>
---------
Co-authored-by: Jeong-Uk,Kim <dnrtoki@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(providers): wait for the ACP command inventory to settle
An ACP agent publishes its slash-command inventory in batches. MiniMax
Code sends its built-in commands first, then merges in every discovered
skill roughly 350ms later. `listCommands()` settled on the first batch,
so a session that had to discover its commands at creation time offered
the 10 built-in commands instead of the 396 the agent eventually
publishes. Every skill was missing from `/` until the session was
reopened and the cached inventory was read again.
Wait for the inventory to go quiet (600ms without another batch) instead
of for the first batch. An empty batch still settles immediately, and
`initialCommandsWaitTimeoutMs` (1500ms default) still bounds the whole
wait for providers that publish once or never publish at all.
* test(acp): verify late commands through the provider boundary
Exercise initial command discovery over real stdio, including a first batch cached before session creation returns. Keep the later skill and subsequent cached read in the same public session contract.
Co-authored-by: huazhongmin <peanut_hzm@163.com>
---------
Co-authored-by: huazhongmin <peanut_hzm@163.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): resolve ACP providers installed after the daemon started
Windows hands a new process the PATH its parent had when it started. The
daemon's supervisor therefore keeps the PATH it inherited at launch, and any
CLI installed afterwards stays invisible to it. A provider installed after the
daemon started reported "not installed" forever, even though the binary was
on PATH in a fresh shell.
Refresh the process PATH from the Windows user/machine registry environment
when the daemon worker starts. Existing entries keep their order and take
precedence; registry entries are appended. This runs once at startup so
PATH-isolated availability checks and explicit env overrides stay
authoritative.
Spawn the absolute path the launcher resolver verified rather than the bare
command. The resolver already finds installs outside the daemon's inherited
PATH (Winget packages, directories added after startup); the resolved path
was previously discarded.
An ACP agent that exits during the handshake never rejects the SDK's
initialize request, so the provider refresh waited out its full 120s deadline
and reported "Timed out refreshing <provider> after 120000ms; pending:
initialize" instead of the child's stderr. Race a child-exit rejection
against initialize so the real failure surfaces.
Also repair persisted MiniMax Code commands. The first catalog entry ran
`npx -y @minimax-ai/code@<version> acp`; npx derives the executable name from
the package name (`code`), but the package publishes `mcode`, so npm exited
before the ACP handshake. The catalog was fixed separately, but commands
already persisted by an older client were never migrated.
* fix(acp): report startup exits across probes and sessions
Extend the shared process failure handler so initialize rejects with stderr after the child exits, including session creation. Keep this fix scoped to startup error reporting; remove the separate PATH and persisted-command changes.
Co-authored-by: peanut_hzm <peanut_hzm@163.com>
* fix(acp): validate provider options before starting probes
Reject malformed options before creating a child or its process-failure promise, so cleanup cannot cause an unhandled rejection in the daemon.
---------
Co-authored-by: peanut_hzm <peanut_hzm@163.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): let a message steered into a running Claude turn be rewound to
A steered message never got a provider message id, because Claude takes it
into the running turn without echoing it back, so rewinding to it refused
with "Cannot rewind before the provider acknowledges the submitted prompt".
The steer admission now reports the uuid Claude minted for the message, and
a Claude conversation rewind to it forks at the entry Claude read it after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(server): keep messages steered into a running Claude turn in the replayed timeline
Claude records a steered message as a queued_command attachment rather than a
user entry, and the history replay skipped it, so every such message, replies
from other agents included, vanished from the timeline after a daemon restart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(claude): verify steer identities across lifecycle tests
Match the accepted-steer contract used by conversation rewind and verify that its identity names the message delivered to the provider.
Co-authored-by: tieo <65707274+tieo@users.noreply.github.com>
* fix(claude): release transcript streams after rewind lookup
Closing readline leaves a partially read transcript open after an early match. Destroy the owned stream on exit and cover repeated lookups with unread data.
---------
Co-authored-by: tieo <65707274+tieo@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* test(plugins): trace recurring global recovery failure
* test(plugins): control cleanup in global switch recovery
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Refresh direct plugin history from authoritative native persistence after conversation/combined rewind, matching the built-in providers' history refresh strategy. Reopen/replay rebuilds translation baselines, rewind tokens and child bindings while preserving outward subscriptions; file-only rewind stays unchanged.
Keep replay internal and replace the manager timeline after it completes. Preserve the committed native handle and close routing across refresh failures so retry and reload recover the retained branch.
The full native session reload is intentionally inefficient, pending a smarter timeline cut that restores translation state, reused IDs, children and permissions without reopening.
Closes#4667
Supersedes #4668 and the rewind-history proposal in #4754.
Verified with 72 targeted tests, green CI, and real OMP browser UI A/B/C -> rewind B -> replacement D with native history/timeline equality and a clean browser reload.
Co-authored-by: Matt Cowger <matt@cowger.us>
Co-authored-by: Omer Cohen <639682+omercnet@users.noreply.github.com>
* test(server): diagnose recurring config responsiveness failure
* test(server): compare profiled and plain config reads on Windows
* test(server): correlate config profiles with long callbacks
* test(server): probe config timing under CPU contention
* test(server): exclude filesystem pool startup from config budget
* test(terminal): finish output before comparing replay captures
A marker can arrive before its trailing newline. Comparing captures taken on either side of that output compares different terminal states. Split that output deliberately and wait for its parsed completion before capturing the expected replay.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* test(terminal): let cleanup fixture exit on request
* test(terminal): capture the Windows record rewrite failure
* test(terminal): repeat Windows cleanup exit diagnostics
* fix(server): reopening a Codex agent no longer reads and holds its full history (#8132)
* fix(server): read Codex history only when Paseo replays it
Reopening a Codex agent whose timeline Paseo still held read the full
thread on connect and kept it on the session until the next replay, which
never came, so every reopened agent held a second copy of its transcript.
thread/resume also returned every turn, and only the sandbox policy was
used from it.
Resume now sends excludeTurns (older Codex ignores the unknown field) and
the history read moves into streamHistory, whose caller owns the result.
A resumed session still needs the earlier turns for rewind targets and the
sub-agent routes that keep an earlier child's interactions on its original
card, so the first turn, goal or rewind indexes the thread and drops the
timeline it read.
* test(server): run reopened Codex agent tests without the Codex CLI installed
* test(terminal): isolate record reader contention on exit
* feat(usage): show when each limit resets, and make usage rows easier to read (#8162)
The reset countdown floored to one unit, so a weekly window read "resets 2d"
from 2d 23h down to 2d 0h and looked stuck for a day; the session window had
the same problem with hours. Countdowns now use two units ("2d 23h", "4h 59m"),
and every row also shows the clock time it resets ("7:20 AM", "Sat 8:00 AM",
"Oct 31, 3:00 PM"), so users can plan work around a reset without hovering.
Rows now put the window name and percent on one line, the bar under it, and the
reset on its own full-width line, so the exact time fits at phone width in
longer languages. The pinned-row background is gone; the pin glyph, drawn in
the foreground colour when pinned, is the only pinned signal. Bars are 6px.
* Make Claude session entrypoint relabeling optional (#8164)
* fix(claude): make session entrypoint relabeling opt-in
Keep inherited SDK and parent identities cleared. Honor the explicit session-open entrypoint contribution so users can opt into the label through a plugin instead of every session receiving it unconditionally.
* test(hub): use standard budget for restart and worktree recovery
The Windows CI scenario timed out at its custom 20-second limit while the other Hub cases took 4–10 seconds each. This scenario starts two daemons and creates, archives and restores a worktree. Use the existing 30-second suite budget without changing any assertions.
* Deliver a steer message that arrives while the previous turn is still starting (#6192)
* Deliver a steer message that arrives while the previous turn is still starting
A steer send that reached an agent before its previous turn had a turn id
found no turn to steer and replaced the starting turn, so the earlier
message never reached the provider. Steering now waits for the starting
turn to be accepted (or fail) and steers the turn it became.
Fixes#6186
* Wake a waiting steer only once the starting turn has an id or its run has ended
A failed start used to wake the waiting steer before its run was cleared,
leaving the later send to replace a run that had already failed.
* Clear a failed start's run even when reporting the failure throws
A steer waiting on that start is released only when the run is cleared.
* Test that a failed start keeps a waiting steer until its run is cleared
* fix(server): steer Codex turns while native identification is pending
Wait for the accepted foreground turn to receive its native ID before steering it. Returning unavailable in this window replaced the turn even after the manager had waited for startup.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(terminal): recover worker records after reader contention
Retain the latest record until a transient sharing failure clears. Deliver exits while publication is pending, await publication before confirming creation, and cancel retries before retirement.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(codex): start custom providers with reserved names
Codex rejects custom provider keys such as ollama before a turn starts.
Namespace the generated keys without changing user-facing provider ids.
Keep older sessions discoverable and select the new key explicitly when
resuming them, so the startup fix does not strand existing conversations.
Closes#6874
Co-authored-by: Egg3901 <rainfordmason@gmail.com>
* fix(codex): keep native sessions out of custom provider imports
* fix(providers): align custom provider example with generated config
Correct the documented internal provider key and simplify import filtering while preserving native and legacy session selection.
* fix(codex): exclude native GCP sessions from custom imports
* test(codex): seed sessions through the portable launcher
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Egg3901 <rainfordmason@gmail.com>
Restore configured terminal history on reconnect, retaining 10,000 rows plus the screen. Serialize the worker-owned xterm buffer directly to ANSI and forward negotiated bounded replay chunks while preserving ANSI-era clients and per-viewer live ordering.
Preserve captured geometry through replay, bound pressure recovery to 500 rows, and keep the omitted visible-history default at 200. Remove the full cell-grid copy and obsolete JSON rendering.
All 21 CI checks pass. Real browser, native Debug emulator/simulator and Linux Electron coverage and platform limits are documented in the PR. The Android Debug invalid native delegate dispatch also reproduces on upstream main; its cause and any change in frequency remain unproven.
Credit Manav Dhindsa (DrakenKor), #6139 and #6148, and Lennart Schoch, #6743, for prior ANSI replay and retention work informing this change.
Closes#6137.
Closes#6147.
* test(server): isolate the reconciliation responsiveness budget
Measure the cold reconciliation in compiled plain Node so unrelated runner callbacks cannot consume its 20ms budget. Retain real filesystem admission and every archival assertion, with unrelated CPU work in the parent as a regression check.
* test(server): initialize probe filesystem support before measurement
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): bound every timeline item so one fetch cannot close the socket
A timeline page is one WebSocket message. Only three tool-call fields were
capped, so MCP results, file contents, errors and merged assistant rows could
make a 20-entry or even a 1-entry fetch pass the outbound high-water mark.
limitAgentTimelineItemContent is now one budgeted walk over any item: 64 KiB
for tool calls, 256 KiB for other items. Over budget, the largest strings are
cut to a shared length with a visible marker and oversized data URLs become a
marker. Fetches also apply it to merged assistant and reasoning rows.
* fix(server): keep short strings whole and typed arrays valid when limiting items
Strings up to 1 KiB are never cut, so a tool call keeps its callId and an
item limits to the same result twice. Arrays drop trailing elements
without inserting a marker element, which typed arrays such as todo items
would reject.
* fix: make sub-agent cards launch markers
Sub-agent tool calls no longer accumulate the child's activity into
`log`. Claude, Codex, OpenCode, OMP and Pi emit the card when the child
starts and when its label or status changes; the child's messages and
tool calls stay in the sub-agent's own timeline. The app no longer
renders a sub-agent log.
The wire schema makes `log` optional. Daemons still send `log: ""` so
apps that require the field keep parsing the card.
* fix(server): put a tintinweb foreground answer in the child timeline
A foreground @tintinweb/pi-subagents child has no session file, so its
answer only exists in the Agent tool result. Emit that text as the
child's assistant message when the child finishes. Tag every sub_agent
producer's `log: ""` with COMPAT(subagent-log) so the shim removal
finds them.
* fix(server): settle child compactions and keep sub-agent cards stable
- Codex: a child compaction shown as loading now completes on the
child's thread/compacted or turn end, once.
- Claude: a streamed child tool call's empty start input is a
placeholder, so the assistant message's input reaches its card.
- OMP: the task card follows only its first child, so later children
no longer re-send an unchanged card.
* fix(server): keep a gotgenes foreground answer on replay
A foreground @gotgenes/pi-subagents child finds its session file only
through the live runtime marker, which history does not keep. Without a
file, emit the spawn result text as the child's assistant message.
* fix(server): respect environment proxies across daemon traffic
Install proxy routing at daemon and plugin process startup, with a separate HTTP agent for outbound WebSockets. Always exempt loopback so local provider bridges remain reachable.
* test(server): run usage source regressions in CI
* fix(server): validate proxy settings without blocking startup
Normalize scheme-less proxies and share HTTP-only validation across fetch and WebSockets. Record ignored variables without credentials in the daemon log. Separate built-in and directory plugin regressions through a typed fixture.
* refactor(server): treat ignored proxy variables as unset
* fix(server): read Windows proxy environment entries once
* fix(server): apply proxy policy to connected host links
* test(server): isolate proxy fixture credential directories
* fix(server): keep proxy routing and authentication consistent
Normalize Windows environment names and wildcard bypass rules at the network boundary. Compare bypass ports numerically and keep Basic proxy credentials on the CONNECT pool, including empty credential fields.
Exclude unrelated callbacks and fixture garbage from the cold event-filter budget. Keep the 20ms limit and IO assertions, with unrelated CPU work as a regression control.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(usage): fetch only when shown and add a host-wide off switch
* fix(usage): restore policy defaults and isolate usage test state
* refactor(usage): give the sidebar footer sole ownership of its summary
Opening a Codex agent whose timeline the daemon doesn't hold asked Codex
for the whole thread in one thread/read reply. Past the 128 MiB provider
line cap that reply killed the session; before the cap it crashed the
daemon. Codex 0.145 and newer reject that read on paginated threads, so
importing them failed.
Paginated threads now load through thread/items/list pages. A legacy
thread keeps its single read. A reply over the line cap fails only its own
request: for a legacy read, a warning row names the archive,
`codex migrate-rollouts`, unarchive steps; for a page, a warning row ends
the history there. Items are capped as they are projected, and rewind's
fork no longer returns the thread's turns.
Co-authored-by: hunterricks <hr@savagestrategic.io>
Co-authored-by: dundunHa <lixinpengde@gmail.com>
* test(plugins): observe global recovery without reloading again
* test(plugins): leave time for recovery failure cleanup
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(server): broadcast agent removals across logical sessions
* test(server): make subscription fixtures portable on Windows
The newly enabled integration suite assumed /bin/cat and a one-second reply deadline, so Windows CI failed before completing its subscription coverage. Use the running Node executable for echo terminals and let diagnostics finish their bounded external tool probes.
Co-authored-by: loganmeyer <50949542+loganmeyer@users.noreply.github.com>
---------
Co-authored-by: loganmeyer <50949542+loganmeyer@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <paseo-bot[bot]@users.noreply.github.com>
* test(server): isolate timeline fetch responsiveness from runner work
Measure the existing cold tail workload in a separate process after fixture collection. Keep the 50ms gate and row assertions, and reproduce unrelated callback CPU contaminating the old measurement.
* test(server): keep timeline probe private and exercise overlapping CPU
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
The responsiveness test timed wall-clock gaps between 1 ms ticks, which reached 50.35 ms on the shared Windows runner for the same code. It now measures main-thread CPU time between ticks and still fails when the payload decodes in one chunk.
Bring in what v0.14.0 shipped: the 0.14.0 entry in CHANGELOG.md and
CHANGELOG.zh-CN.md exactly as tagged (replacing the 0.14.0-beta.2 series
entry), the 0.14.0 version in every package.json and package-lock.json, and
the generated F-Droid changelogs. The unreleased notes on main stay above the
entry and now say they are not in 0.14.0.
Release commit: 8c6de842a3 (tag v0.14.0)
* fix(pi): settle edxeth subagent lifecycle events
* test(pi): preserve completed children when restoring captured histories
Verify the completed child and assistant transcript through history replay and the store consumed by clients. Both captured completion protocols otherwise leave a running descriptor.
Co-authored-by: Zeno_ <lin1071833138@gmail.com>
---------
Co-authored-by: Zeno_ <lin1071833138@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* Deliver a steer message that arrives while the previous turn is still starting
A steer send that reached an agent before its previous turn had a turn id
found no turn to steer and replaced the starting turn, so the earlier
message never reached the provider. Steering now waits for the starting
turn to be accepted (or fail) and steers the turn it became.
Fixes#6186
* Wake a waiting steer only once the starting turn has an id or its run has ended
A failed start used to wake the waiting steer before its run was cleared,
leaving the later send to replace a run that had already failed.
* Clear a failed start's run even when reporting the failure throws
A steer waiting on that start is released only when the run is cleared.
* Test that a failed start keeps a waiting steer until its run is cleared
* fix(server): steer Codex turns while native identification is pending
Wait for the accepted foreground turn to receive its native ID before steering it. Returning unavailable in this window replaced the turn even after the manager had waited for startup.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(claude): make session entrypoint relabeling opt-in
Keep inherited SDK and parent identities cleared. Honor the explicit session-open entrypoint contribution so users can opt into the label through a plugin instead of every session receiving it unconditionally.
* test(hub): use standard budget for restart and worktree recovery
The Windows CI scenario timed out at its custom 20-second limit while the other Hub cases took 4–10 seconds each. This scenario starts two daemons and creates, archives and restores a worktree. Use the existing 30-second suite budget without changing any assertions.
* fix(server): read Codex history only when Paseo replays it
Reopening a Codex agent whose timeline Paseo still held read the full
thread on connect and kept it on the session until the next replay, which
never came, so every reopened agent held a second copy of its transcript.
thread/resume also returned every turn, and only the sandbox policy was
used from it.
Resume now sends excludeTurns (older Codex ignores the unknown field) and
the history read moves into streamHistory, whose caller owns the result.
A resumed session still needs the earlier turns for rewind targets and the
sub-agent routes that keep an earlier child's interactions on its original
card, so the first turn, goal or rewind indexes the thread and drops the
timeline it read.
* test(server): run reopened Codex agent tests without the Codex CLI installed
Measure config reads in a fresh process so unrelated runner callbacks cannot consume the config CPU budget. Keep the existing budget, result, async I/O and yield assertions, and prove isolation with a busy parent callback.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* docs(changelog): fold 0.14.0-beta.2 UI fixes into the 0.14.0 entry
(cherry picked from commit 28bb7e29be)
* chore(release): cut 0.14.0-beta.2
(cherry picked from commit 1a05491be5)
* docs(changelog): keep unreleased main changes out of the 0.14.0-beta.2 entry
The beta.2 tag was cut from a selective hotfix branch, so #8100, #8117 and #8081 are on main but not in beta.2. Every changelog parser (app, website, release-notes sync) skips the preamble, so listing them there keeps them out of the beta.2 release body and What's new until the next release entry absorbs them.
* feat(server): resume interrupted agents after host restart
Continue saved running conversations after graceful restart or crash, with host opt-out and a configurable continuation prompt. Preserve explicit launch overrides when reopening the same provider session.
Co-authored-by: coolwind <45729206+coolwindX@users.noreply.github.com>
Co-authored-by: suntianc <suntc8985@gmail.com>
* fix(app): translate restart recovery host settings
* test(app): synchronize sidebar drags and clean up added projects
Wait for the drag sensor click blocker to expire before the next user action. Resolve UI project keys to daemon IDs for cleanup so empty projects do not contaminate later sidebar tests.
* fix(app): tuck the resume prompt behind an edit sheet
Match the System prompt row: an Edit button left of the restart recovery
switch opens the prompt in a sheet, and is disabled while resume is off.
* fix(server): resume interrupted agents without holding startup
Startup now only chooses resume candidates before anything else reads or
repairs persisted running state. Reopening and prompting run in the
background after connections open, so a provider that is slow to reopen
holds back only its own agent. Finish observation waits for a pending
child's resume, so parents are not told the child was closed meanwhile.
* style(server): format restart resume e2e test
* test(server): wait for the fetch result before advancing the narrow refresh debounce
The test released the held fetch, flushed six microtasks, then advanced
the 1s refresh debounce. When the fetch result landed after that advance
(slow Windows runners), the debounce started late and vi.waitFor's
auto-advance reached it only at its real-time timeout. Wait on the
service's in-flight fetch count instead, as the sibling test does.
* test(server): retry stalled OpenCode fixture downloads within the test budget
npm abandons a stalled registry download only after its 300s default
fetch timeout, past the install's 180s budget. The killed install left
the fixture directory locked on Windows, so cleanup failed with EBUSY and
hid the timeout. Against a registry proxy that stalls the first tarball,
a default install hung 225s; with --fetch-timeout it retried and finished
in 16s.
---------
Co-authored-by: suntianc <suntc8985@gmail.com>
The migration case runs real Git operations and several plugin subprocess restarts. Windows CI exceeded its 30-second test deadline and entered cleanup while the operation was still active. Keep every assertion and allow 60 seconds for the complete workflow.
* Keep an interrupted background Claude subagent canceled after a daemon restart
Replay read a background Agent call's immediate async-launch result as the
child's outcome, so every background subagent restored as completed. Skip that
result, and read a child transcript that ends on the interrupt placeholder as
canceled, which is what the live path reported.
* Keep a background Claude subagent running when it got a new prompt after an interrupt
* fix(claude): preserve background subagent outcomes on replay
Use persisted task notifications as replay outcomes with the live status mapping. Diagnostic API request copies contain launch tool results without async metadata, so only transcript messages supply task declarations and tool outcomes.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Release cumulative plugin snapshots after adapter attachment and retain canonical replay items. Preserve Unicode text, root/child ordering and current tool state; release history on close.
Co-authored-by: suntianc <suntc8985@gmail.com>