Commit Graph
6277 Commits
Author SHA1 Message Date
Mohamed Boudra 301b49e381 test(server): removal of auto_accept returns ACP to asking; Claude keeps opening restrictions across a patch 2026-11-01 15:22:56 +01:00
Mohamed Boudra ee936d51c0 test(server): assert the forwarded plugin setting without nesting callbacks 2026-11-01 15:21:02 +01:00
Mohamed Boudra 8e28e3988b test(server): a setting a plugin changes on its own is forwarded as options_changed 2026-11-01 15:20:05 +01:00
Mohamed Boudra 62df2f3253 test(server): a patch key is resolved against nested configured defaults 2026-11-01 15:18:24 +01:00
Mohamed Boudra aba0c78449 docs(server): a rejected apply reports what the provider moved after the call ends 2026-11-01 15:15:20 +01:00
Mohamed Boudra a0754e9f9b fix(server): fold an old app's profile featureValues by the provider and options the write carries
A write with options folds featureValues over those options. A write
without them patches the stored options, unless the profile moved to
another provider, which starts from no options.
2026-11-01 15:15:20 +01:00
Mohamed Boudra 9d8747cd3a fix(server): Claude reports Fast as off, not removed, when a model switch drops it
A removed key lets a config.json default of fast_mode: true fill back in
while Fast is off at runtime.
2026-11-01 15:15:20 +01:00
Mohamed Boudra 13ad4a13ff fix(server): providers validate live option patches and Claude reports Fast dropped by a model switch
Live patches go through the schema used at creation. A Claude model switch
that cannot keep Fast reports fast_mode as removed so the stored options
match the session.
2026-11-01 15:10:35 +01:00
Mohamed Boudra 9de8cbf2b8 fix(server): ACP reports the selects it moved during open or apply as that call's result
A config_option_update that arrived before the write response was emitted
as an event on top of the result the manager stores. Notifications during
open or apply now fold into the open patch or apply result, and a rejected
apply reports what the agent moved since nothing is stored. Live options
are validated with the creation schema. Tests drive a stdio ACP agent.
2026-11-01 15:10:35 +01:00
Mohamed Boudra 2dd83e43cb fix(server): apply an old app's profile featureValues over the profile's stored options
The unchanged app's profile form only knows the controls, so a name-only
edit dropped options it never shows, such as sandbox_mode. Its
featureValues now apply as a patch over the options already stored for the
profile (null removes a key), and a write with no featureValues keeps them.
2026-11-01 15:10:35 +01:00
Mohamed Boudra ac6b5440e8 refactor(server): providers return what apply and open ended with instead of reporting it afterwards
applyOptions returns the options the session ended up with and the session
exposes its open difference as openOptionsPatch, so the manager stores the
patch and the provider's answer in one step. Removal is an ordinary patch:
the provider receives the default the key falls back to, or null, and returns
what it kept. Controls no longer take a default from a stored legacy feature
value.
2026-11-01 14:55:27 +01:00
Mohamed Boudra 0da2781520 refactor(server): providers report option differences once, after create, resume and apply
Providers used to write their own reports into the agent's options while a session was being
created, resumed or updated, which needed a growing set of reconciliation, baseline and
suppression rules to stay in step with the daemon.

The contract is now transactional. A provider opens or updates with the options it is given and
emits nothing while doing so; if the result differs it says so once, afterwards, as
`options_changed`. Live apply hands the provider only the keys the patch sets and the daemon stores
them onto the agent's current options when the provider accepts, so the last write wins. A change
the provider makes on its own is stored and forwarded, not undone. Removing an option drops the key
and sends nothing live. Controls carry no state; `options` is the only option state.

A legacy `agent.create.before` hook's `featureValues` edits are applied as a patch over the
returned options, so its deletions and replacements hold. The unreleased `aliases` field on option
choices is gone; a pre-v0.10 Codex Fast preference is reported once as the model's tier id.
2026-11-01 14:40:11 +01:00
Mohamed Boudra f487316a9d chore(website): regenerate the config schema for profile options 2026-11-01 08:17:11 +01:00
Mohamed Boudra 1ee149c85b fix(server): show Fast for a stored Codex fast_mode: true without rewriting the record
Reverts the storage migration from a987b4a43. The Codex speed control now takes its default from
the session's current options with the same rule the runtime uses (an explicit service_tier wins;
fast_mode: true applies only while service_tier is absent). This holds on create, resume, live
apply and for config.json defaults, and stored options stay as set.
2026-11-01 07:53:29 +01:00
Mohamed Boudra 72d488f17a fix(server): read a pre-v0.10 Codex fast_mode record as service_tier "fast" and store it that way
A record holding `fast_mode: true` without `service_tier` ran Fast but the speed control showed
Normal, and picking Normal then wrote "default". The Codex session now normalizes the old boolean
at construction and reports the new shape through its existing options_changed event.
2026-11-01 07:53:29 +01:00
Mohamed Boudra 8e83d9346a fix(server): keep snapshot options as configured, restore OMP baseline, cover options through public interfaces
- Codex: drop displayOptions; a select choice may carry aliases so a saved Fast preference selects the model's Fast tier from options + controls alone.
- OMP: removing fast_mode restores the runtime's starting setting.
- ACP/Cursor removal tests run through real session initialization.
- agent.config.apply of a non-control option reaches the provider and shows in the next snapshot (daemon e2e).
- Daemon config store persists legacy-featureValues profiles as options on the next profile save.
2026-11-01 07:53:29 +01:00
Mohamed Boudra 6c22bc72df fix(server): address Phase 1 audit findings on option controls
- Removing auto_accept (OpenCode, ACP) turns live approval off; ACP selects return to their session default.
- agent.create.before hook featureValues edits override options the create already set.
- Claude commits fast_mode only after the runtime accepts it.
- Codex snapshots show a saved Fast preference as the tier the model resolves it to (AgentSession.displayOptions).
- Profiles are folded into options in the daemon config store; the config API still answers with featureValues.
- Snapshot options and provider.controls.list carry all effective options.
- Test: Claude fast_mode survives a restart through stored providerOptions.
2026-11-01 07:53:29 +01:00
Mohamed Boudra bc00edf904 feat(server): fold featureValues into providerOptions and describe composer controls
Providers emit option controls over top-level providerOptions keys; the daemon stores one
options record per agent, merges config.json defaults as effective values, and applies patches
live via AgentSession.applyOptions. Legacy featureValues (wire, stored records, profiles,
schedules, hooks, MCP) fold into providerOptions; snapshots still carry features built from
controls. Snapshot options expose only keys that have a control.
2026-11-01 07:53:29 +01:00
Mohamed Boudra afce426a43 feat(protocol): option controls, options patch, and provider.controls.list
Add AgentOptionControl descriptors, snapshot options/controls, an options patch on
agent.config.apply, provider.controls.list RPC, and server_info.features.providerOptionControls.
featureValues stays accepted on the wire (COMPAT).
2026-11-01 07:53:28 +01:00
paseo-bot[bot]andDominic Anaeto 14519bdb5b Read archived Pi chats after their working folder is removed (#8442)
* 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>
2026-11-01 06:52:48 +00:00
Mohamed Boudra 891e62309c fix(release): use the keychain password for macOS signing setup (#8445)
Backport the pinned packaging tool correction in the workflow so existing release tags can be rebuilt without changing their dependencies.
2026-11-01 13:35:11 +07:00
paseo-bot[bot] 6ae6308cfb test(server): control failed Git clone responses in credential test (#8428)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 06:01:30 +00:00
Mohamed Boudra ef77b823ae chore(release): reconcile 0.15.0-beta.1 metadata (#8443)
* docs(changelog): prepare 0.15.0-beta.1

(cherry picked from commit 7e5ad53491)

* chore(release): cut 0.15.0-beta.1

(cherry picked from commit 8bd38fb236)

* test(docs): follow nested worktrees page
2026-11-01 12:56:41 +07:00
Mohamed Boudra 60f29a4350 docs(worktrees): add nested worktreeinclude reference 2026-11-01 06:31:01 +01:00
paseo-bot[bot]andDominic Anaeto 8efb21f55c fix(server): close abandoned workspace service connections (#8421)
* 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>
2026-11-01 03:55:48 +00:00
paseo-ai[bot] b2666a0aec fix: update lockfile signatures and Nix hash [skip ci] 2026-11-01 03:43:24 +00:00
Mohamed Boudra 82d5f6c580 fix(app): keep layout sized to the window after rotation (#8377)
A style update racing a window resize could recommit old root constraints. Rebuild the style update from the current root on each commit attempt.
2026-11-01 10:34:06 +07:00
Mohamed Boudra da75aa7a4a Fix terminal emoji size and alignment (#8375)
* 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.
2026-11-01 10:33:59 +07:00
86c60d367c fix(claude): keep a resumed subagent on its row after the session reopens (#8408)
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>
2026-11-01 01:05:02 +00:00
paseo-bot[bot] 5afa1a9f8e test(server): isolate cold Git filter from control work (#8397)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 00:01:29 +00:00
paseo-bot[bot]andOkan YILDIRIM 2d7adfc450 fix(app): restore directory subscriptions after demand returns (#8403)
Invalidate refresh satisfaction when subscriptions are released, and retry
if demand returns before the overtaken refresh completes. Otherwise the
same connection source can stay satisfied with no live list listeners.

Cover both demand sources and completion orderings with live delta checks.

Co-authored-by: Okan YILDIRIM <63511519+ragokan@users.noreply.github.com>
2026-10-31 23:58:14 +00:00
paseo-bot[bot] 7d9741ef77 fix(app): expose the SSL checkbox checked state on web (#8399)
The web renderer does not map accessibilityState.checked onto aria-checked. Supply the checked property explicitly so accessibility clients agree with the checkmark and connection URI.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-31 22:50:27 +00:00
paseo-bot[bot]andluke caf9300358 fix(server): preserve running status after agent creation (#8396)
* 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>
2026-10-31 20:52:07 +00:00
f0dfb9134c fix(app): keep the open workspace visible in collapsed groups (#8395)
* fix(app): keep the open workspace visible in collapsed sidebar groups

A collapsed group showed its first seven rows plus working and
needs-attention rows, so an idle open workspace past the limit was
hidden behind Show more and no sidebar row was highlighted.

selectSidebarGroupVisibility now takes the route selection. When the
collapsed limit would hide the open workspace, it is returned as
leadingItem and rendered first in project groups, status groups and
both Pinned sections. Rows the group already shows stay in place,
expanded groups keep group order, and drag lists render the leading
row outside their sortable data, so a reorder never saves its borrowed
position.

Refs #8078

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(app): keep shortcut targets visible in collapsed groups

The navigation journey still required the selected overflow workspace to stay hidden. Assert its visible selection while preserving collapsed-group navigation and the seven ordinary rows.

Co-authored-by: 0xRoy <1997roylee@gmail.com>

---------

Co-authored-by: 0xRoy <1997roylee@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>
2026-10-31 20:03:31 +00:00
paseo-bot[bot]andJeong-Uk,Kim 56c051503b fix(server): keep promptless Codex agents usable after reopening (#8393)
* 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>
2026-10-31 18:56:22 +00:00
paseo-bot[bot] 85354fcb6a test(terminal): verify cleanup by process identity (#8389)
* test(terminal): capture recurring worker publication failures

* test(terminal): diagnose the remaining process cleanup wait

* test(terminal): verify cleanup by process identity

* test(terminal): retain native liveness proof during cleanup checks

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-31 18:38:48 +00:00
QTomandClaude Opus 5.5 2dd931c8bd fix(app): accept host:port and URLs in the direct connection host field (#8223)
The direct connection form treated any host containing a colon as a bare
IPv6 address, so entering "100.66.69.36:6767" or "tcp://host:6767" built
"tcp://[100.66.69.36:6767]:6767" and surfaced the browser's raw "Invalid URL"
error. Normalize the host input first: strip a leading scheme and any
path/query/fragment, split "host:port" (the inline port wins), and only treat
unbracketed hosts with two or more colons as IPv6.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 18:06:12 +00:00
QTomandClaude Opus 5.5 58eafd81e5 fix(app): fall back to native terminal copy/paste without the Clipboard API (#8230)
Browsers omit navigator.clipboard outside secure contexts, such as the daemon web UI served over plain http on a Tailscale or LAN address. The non-Mac Ctrl+C/Ctrl+V terminal shortcuts then threw synchronously, and Ctrl+V had already prevented the native paste, so terminal copy/paste broke. When the Clipboard API is unavailable, the shortcuts now leave the default action alone so xterm's native copy/paste event handlers do the work, and the browser clipboard rejects instead of throwing.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:01:27 +00:00
paseo-bot[bot]andhuazhongmin eab9ac3b03 fix(acp): include late-discovered skills in initial command lists (#8387)
* 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>
2026-10-31 16:07:08 +00:00
paseo-bot[bot]andpeanut_hzm e02fa9a5f8 fix(acp): report provider startup exits without waiting for timeout (#8384)
* 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>
2026-10-31 14:55:17 +00:00
b117e3fb0f fix(claude): allow conversation rewind to messages sent during a turn (#8372)
* 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>
2026-10-31 13:03:27 +00:00
paseo-bot[bot] 2ac288f4d0 test(plugins): make global switch recovery deterministic (#8342)
* 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>
2026-10-31 12:26:32 +00:00
Mohamed Boudra 1008e9fffc Insert suggested commands into the composer (#8371)
* feat(composer): insert suggested commands into drafts

* fix(composer): close suggestions after command insertion

* fix(composer): place caret after inserted commands
2026-10-31 19:25:16 +07:00
Matt CowgerandMohamed Boudra 74613e4bc3 feat(opencode): reuse running OpenCode v2 services (#7435)
* feat(opencode): connect v2 client to an existing server

* feat(providers): reuse running agent servers

Keep shared server sessions isolated and retain native tools while refreshes reuse the running service.

* fix(providers): recognize formatted bridge manifests

Managed plugin ownership must survive harmless JSON formatting changes.

* test(providers): distinguish isolated session bindings

Use separate session identities to verify that dedicated helpers keep their environments isolated.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-10-31 18:55:24 +07:00
paseo-bot[bot]andOuyang Xingyuan 0e5bcbd9f5 fix(app): open relative chat links inside nested repositories (#8361)
* fix(app): open a nested-repo file when the workspace-root path is missing

A workspace that contains another git repo often gets paths written
relative to that nested repo. `schema/x.md` is really
`repo-a/schema/x.md`. A markdown link was joined onto the workspace
root and opened a missing file. Inline code already asked the daemon
for a suffix match.

Resolved workspace-relative paths that contain a slash now use that
same lookup before opening. An exact hit stays on the original path.
A suffix hit replaces it and keeps the line range. A failed lookup
still opens the original path. Bare names, absolute paths, and `~/`
paths are unchanged.

Example:
- Input: workspace `/repo`, link `schema/x.md`, file at `repo-a/schema/x.md`
- Before: open `/repo/schema/x.md` (missing)
- After: open `/repo/repo-a/schema/x.md`

* fix(app): preserve explicit destinations when finding nested files

Relative chat links can name a file inside a nested repository. Retain the suffix lookup while using the original href and document base to preserve absolute paths, preview links, and folder destinations.

Co-authored-by: Ouyang Xingyuan <galaxyroaming@qq.com>

* fix(app): keep network share links on their absolute destination

Use the shared absolute-path classifier so network share hrefs retain their destination alongside drive and POSIX paths.

* fix(app): keep nested-file lookup inside ordered path opening

Resolve the original directory before considering suffix matches, and allocate click ordering before asynchronous lookup. The existing opener now owns the complete operation so a slow earlier click cannot replace a later selection.

* test(app): load UI modules before test lifecycle hooks

Cold module transformation exceeded the lifecycle hook deadline before these suites could run. Complete module initialization before registering the tests, retaining their assertions and timeout settings.

---------

Co-authored-by: Ouyang Xingyuan <galaxyroaming@qq.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-31 11:05:06 +00:00
a7d9bb34fc fix(plugins): keep rewound conversations on their retained branch (#8368)
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>
2026-10-31 17:48:42 +07:00
Mohamed Boudra fd65985e9d fix(android): resize header fades after rotation (#8349)
Clear Android SVG descendant geometry caches when the canvas resizes. Cover growth and shrinkage with a native pixel-rendering regression.
2026-10-31 14:45:13 +07:00
Mohamed Boudra 254166e7c1 feat(terminal): add native selection handles (#8348)
* feat(terminal): add native selection handles

* fix(terminal): preserve selection at row boundaries

* fix(terminal): preserve selection boundary when handles cross
2026-10-31 14:23:10 +07:00
paseo-bot[bot] 9c5b47421a test(server): exclude filesystem startup from config responsiveness (#8296)
* 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>
2026-10-31 06:49:47 +00:00
paseo-bot[bot]andMohamed Boudra 3b51b8ab2e Recover terminal worker records after Windows reader contention (#8155)
* 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>
2026-10-31 06:31:08 +00:00