Commit Graph
5286 Commits
Author SHA1 Message Date
Okan YILDIRIM 930ded5e1a fix(codex): include patch details in file change approvals 2026-11-02 18:04:00 +00:00
7495c20f78 fix(app): keep HTML section links inside the preview (#8559)
* fix(app): keep HTML preview fragment links inside the preview

A file previewed through `srcDoc` resolves `<a href="#section">` against the
app's URL, so the link loaded Paseo inside the iframe and the preview became
the Welcome screen. Handle same-document fragment clicks from a small script
in the preview document, and let the page's own handlers go first.

Closes #7465

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

* fix(app): preserve native HTML fragment navigation in previews

Give each HTML preview its own document URL so section links resolve within the file. Browser default navigation preserves cancellation by page handlers without an injected click interceptor.

Co-authored-by: 3ae3ae <ogyshjsm@naver.com>

---------

Co-authored-by: 3ae3ae <ogyshjsm@naver.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-02 15:54:49 +00:00
Mohamed Boudra b92a34ab3d Keep reconnecting and updating status visible in native chats (#8568)
* fix(app): keep chat status toasts visible below floating headers

Compact native chats extend beneath the floating header. Panel toasts need measured header clearance and a layer above its fade; placing them below the fade leaves an excessive gap. Keep dock overlays outside keyboard translation so opening the keyboard cannot move them offscreen.

* test(app): verify rendered chat status spacing on native devices

Measure the real header and toast bounds with the software keyboard closed and open. The former arithmetic helper test passed even when the viewport stopped consuming header clearance; the native regression fails against that broken production wiring.

* test(app): exercise toast placement through host disconnection

Observe the public reconnecting state with host connectivity interrupted externally. Keep native bounds and software keyboard assertions while removing runtime evaluation and private timeline-owner mutations.
2026-11-02 22:49:53 +07:00
paseo-bot[bot]andRyan Winograd 8018231a00 fix(pi): release archived chat runtimes after history replay (#8554)
* fix(pi): close history-only runtimes after replay

Archived timeline reads resume a Pi RPC process to reconstruct the saved
conversation. The history-only session remained open after replay, so
browsing or synchronizing archived agents left one idle Pi process per
agent.

Mark history-purpose resumes for closure and close the runtime in
streamHistory's finally path. Interactive sessions remain resident, and
idempotent close keeps later manager cleanup safe.

* fix(pi): preserve history cleanup across current resume behavior

Keep the original session identity and missing-folder cleanup when releasing
history-only runtimes. Use an existing directory in the regression so the
newer resume fallback does not try to copy a nonexistent session fixture.
Cover interrupted and failed replay, interactive residency, and automatic
cleanup of a missing-folder history copy.

Co-authored-by: Ryan Winograd <ryan@thewinograds.com>

* test(pi): separate stopped and failed history replay cases

---------

Co-authored-by: Ryan Winograd <ryan@thewinograds.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 14:53:40 +00:00
555818f5f7 fix(acp): clear abandoned approvals without leaving providers blocked (#8548)
* fix(acp): clear permission requests a finished turn abandoned

An ACP agent can give up on a permission request itself and end its turn
normally. Paseo kept that request pending, so the approval card stayed up
with nothing listening, and the next prompt reported the agent as waiting.

Cancel a turn's open requests whenever that turn ends, cancel a request
when its tool reaches a terminal status, and publish the resolved event in
both cases. Requests raised outside a turn stay answerable.

Closes #7664

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

* fix(acp): keep permission cleanup consistent after failed turns

Failed and canceled turns clear every permission in the agent manager. Answer that same set in the ACP session so a request raised outside the foreground turn cannot leave the provider waiting after its approval disappears.

Co-authored-by: 3ae3ae <ogyshjsm@naver.com>

---------

Co-authored-by: 3ae3ae <ogyshjsm@naver.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-02 13:22:46 +00:00
paseo-bot[bot] 27caf913f6 test(server): trim subdirectory setup fixture overhead (#8558)
Exercise setup against an existing checkout instead of constructing Git history and a worktree inside its deadline. Preserve the real shell command and both output-location assertions.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 12:53:00 +00:00
paseo-bot[bot] 835bc49487 fix(claude): retain final usage when a turn fails (#8519)
Non-success SDK results computed final token counts and cost but emitted only failure. Publish the existing usage update before the terminal event so clients retain completed work accounting.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 08:59:37 +00:00
Mohamed Boudra 63302287fe Fix plugin RPCs with schema transforms (#8550)
* fix(plugins): parse RPC values once at the receiver

Sending parsed values caused transforms to run again on incompatible schema outputs. Keep the wire values in schema-input form and parse only where consumed.

* fix(plugins): let omitted RPC inputs reach schema defaults

* fix(plugins): accept omitted RPC outputs for client defaults
2026-11-02 15:42:39 +07:00
paseo-bot[bot]andhadan8977 3e3a707f5a Keep moved file paths and diffs intact in commit history (#8509)
* fix(server): keep commit file paths when a file moves up a directory

* test(git): open moved commit files through their listed path

Verify commit history and diff lookup agree for files moved up a directory, with and without content edits.

Co-authored-by: hadan8977 <zc-huang23@mails.tsinghua.edu.cn>

* refactor(git): clarify compact rename handling and test cases

Co-authored-by: hadan8977 <zc-huang23@mails.tsinghua.edu.cn>

---------

Co-authored-by: hadan8977 <zc-huang23@mails.tsinghua.edu.cn>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 07:58:56 +00:00
Mohamed Boudra d4ac64f335 Let plugins stream live events and binary data to the app (#8527)
* feat(plugins): stream events and bytes between plugins and the app

Plugins can declare a subscription with defineSubscription, handle it with
server.handle(contract, (input, { push, signal })), and listen from a surface
with useSubscription or client.subscribe. A top-level Uint8Array in an event,
an RPC output, or an RPC input crosses the wire as a binary frame (opcodes
0x20-0x2f) without JSON or base64; a nested one fails validation on the sender.

Each subscriber runs its own handler, owned by the session that subscribed,
so release, disconnect, plugin stop and reload need no plugin code. The
runtime buffers pushes until the subscribe response has gone out, so a client
never sees an event for a subscription it does not know yet.

Gated on server_info.features.pluginSubscriptions; binary outputs reach only
clients that advertise plugin_binary_payloads.

* fix(plugins): close subscription gaps found in review

- Losing daemon.manage now releases the session's plugin subscriptions;
  binary events bypass the outbound permission check, so streams would
  otherwise outlive the revocation.
- A subscribe that times out sends unsubscribe, since the plugin may
  still start the handler after the daemon gave up.
- The byte limit leaves room for the largest frame header and routing,
  and lives in assertPluginWireValue so events, outputs and inputs share it.
- A release right after the host accepted keeps `ready` resolved, so a
  handler that returns at once reports closed rather than an error.
- Session trace logging tolerates loggers without isLevelEnabled.

* fix(plugins): withhold binary plugin results after plugin access is revoked

A binary RPC output or event skipped the outbound permission check its
JSON form passes, so an RPC in flight when daemon.manage was revoked still
delivered its bytes. Each frame now checks the permission of the JSON
message it stands in for.

* test(plugins): cover subscriptions in a real browser instead of JSDOM

The app subscription tests mounted hooks in JSDOM, which docs/testing.md
rules out. The adapter and contract behavior is now a plain unit test,
and a Playwright spec drives the diff-watch and media-stream examples:
JSON events following file changes, streamed bytes, and an upload.

* test(plugins): add the plain subscription unit test and the browser spec

* fix(plugins): apply subscription schema transforms once

Both ends parsed each subscription value, and the sender sent its parse
output, so the receiver parsed a schema's output as fresh input. An event
schema like z.string().transform((s) => s.length) closed the stream as
invalid. The sender now validates and sends the value as given; the
receiver's parse produces what the handler or callback sees.

* fix(plugins): parse a subscription's input once in the plugin process

server.handle wrapped subscription handlers in a second input parse, so a
transforming input schema rejected its own parsed output before the
handler ran.
2026-11-02 14:10:15 +07:00
Mohamed Boudra 70cb34927a fix(app): keep question choices open until explicit navigation (#8525)
Allow description clicks to select options while users copy text. Removing automatic advance keeps that interaction reversible; links remain independent and submission stays explicit.
2026-11-02 14:08:07 +07:00
paseo-bot[bot] b280ca5355 fix(relay): keep local E2E tests independent of production upstream (#8514)
Wrangler local mode retains deployment vars, so relay readiness probes were forwarded to an unavailable upstream instead of the local Durable Object. Clear that binding only in the E2E launcher.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 13:59:19 +07:00
da8d58bfee fix(plugins): preserve agent message provenance in timeline transforms (#8492)
Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 05:04:23 +00:00
Mohamed Boudra 7c2812dde6 fix(app): add hosts without leaving the current screen (#8512)
* fix(app): add hosts without leaving the current screen

A retained Settings route replayed its addHost query after appearance remounts. Own the connection flow outside screen lifetimes and let each consumer choose its completion navigation.

* fix(app): release the project dialog before adding a host

* fix(app): size the QR scanner viewport on wide layouts

* test(app): align creation and desktop setup with in-place host flow
2026-11-02 11:07:48 +07:00
Mohamed Boudra b474beedce Homepage shows an agent building a plugin live (#8515)
* feat(website): show agents building plugins on the homepage

The plugins section now leads with the workflow instead of the API list:
you ask an agent for a panel and it appears, without a restart. It plays
as a timeline (prompt, tool calls, result) and then slides in the panel
the agent built, followed by the 400+ community plugins and their
categories. It moves above the automation section.

Mock tool calls on the homepage now match the app's collapsed timeline
rows: same labels and icons, muted text in the UI font, and Paseo MCP
tools named by action ("Create agent"). The hero pills are now nouns.

* fix(website): show the finished plugin demo when motion is reduced

The demo staged its items and slid the panel across its width even for visitors who ask for reduced motion. It now starts in its finished state for them, matching the hero mockup.
2026-11-02 10:50:12 +07:00
e2f0779379 Render Markdown tables written directly below prose (#8485)
* fix(app): render tables immediately after paragraphs

Insert a paragraph break before GFM tables adjacent to prose so MD4C
recognizes them, preserving quote/list containers and line endings.

* fix(app): preserve table headers during source adaptation

Replace the preceding line ending when inserting a table separator.
This keeps the separator before the header's source range, so entity
and local image edits cannot consume the paragraph break.

---------

Co-authored-by: Okan YILDIRIM <63511519+ragokan@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: thsrite <thsrite@gmail.com>
Co-authored-by: Woosuk Nam <me@suk.kr>
2026-11-02 03:30:52 +00:00
paseo-bot[bot] a166a3317a test(terminal): check original processes after protocol cleanup (#8502)
Startup launches another worker after closing obsolete protocols, so a reused numeric PID does not prove the original process survived. Check the recorded birth identities and require cleanup to be confirmed.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 03:01:36 +00:00
paseo-bot[bot]andNoah efc64a5443 Explain the mode required to create agents on another provider (#8483)
* fix(server): say when create_agent needs an explicit mode

* test(server): verify cross-provider mode discovery through the daemon

Exercise the MCP contract, refusal without a child, provider inspection, and explicit-mode creation through the public daemon interfaces. Qualify unattended advice because targets without an unattended mode still require an explicit choice.

Co-authored-by: Noah <noahguerin20@gmail.com>

* test(server): run mode discovery in the integration suite

The unit command excludes E2E files, and CI integration uses an explicit list. Add the cross-provider MCP regression to that existing list so CI exercises its guidance, refusal, discovery, and retry assertions.

---------

Co-authored-by: Noah <noahguerin20@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 02:08:31 +00:00
7efa14238d fix(claude): report API-error turns as failed (#8480)
* fix(claude): fail a turn that Claude Code ends on an API error

Claude Code reports a turn that stopped on an API error (a session or
usage limit, an invalid key, an overloaded request) as a `success`
result with `is_error: true`, the error text in `result`, after a
synthetic assistant reply carrying the same text and an `error` field.
The provider read only the subtype, so the turn completed with the
error as its answer: the agent went idle with no lastError and showed
as finished in the sidebar.

Treat such a result as a failed turn with the result text as its
error. Hold the synthetic error reply back until the result arrives so
the failure row does not repeat it; a reply the turn moves past, or a
result without is_error, still shows it.

Co-authored-by: RoundRedDot <roundreddot@gmail.com>

* fix(claude): retain final usage when an API-error turn fails

Publish the converted result totals before the failure event so the
existing usage handler preserves work done earlier in the turn.

---------

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-02 01:07:00 +00:00
paseo-bot[bot] dbbcb103ba fix(opencode): preserve denial reasons when a message supersedes approval (#8477)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 23:50:55 +00:00
Thomas VanandClaude Opus 5.5 7f318bf7cf fix(codex): end an interrupted turn's shell commands (#7525)
`turn/interrupt` ends a Codex turn and leaves the shell commands it started running: a
command the user just stopped runs on to its own end, alongside the next turn.

Once Codex accepts the interrupt, the provider now ends each command the interrupted turn
started that has not exited, by process id, with `thread/backgroundTerminals/terminate`,
and a turn Paseo starts waits for those calls before its `turn/start`.

- Attribution: `thread/backgroundTerminals/list` carries no turn, so the provider records
  each root-thread `commandExecution` process id under the turn of its `item/started`. A
  `completed` item drops its id; a `failed` one keeps it, because Codex reports an
  interrupted turn's still-running command as failed. A turn that ends any way but
  `interrupted` forgets its ids, so what an earlier turn left running on purpose is never
  ended. At most 16 turns are remembered.
- A late command: the turn keeps its accepted interrupt, so a command whose `item/started`
  arrives after Codex accepted the interrupt (one queued behind an earlier notification's
  conversion, for instance) is ended as soon as it is seen. Each process is terminated
  once, and a turn start waits for every pending sweep.
- It never sends `thread/backgroundTerminals/clean`, which ends every terminal on the
  thread. It ends nothing after an already-idle interrupt, nothing on a subagent's thread,
  and nothing after an interrupt of a turn Codex never identified.
- Bounds: each terminate times out after 2 s; a failure is logged
  (`provider.codex.interrupt.terminal_terminate_failed`) and fails nothing. `startTurn`
  waits at most the interrupt's bound plus one terminate's plus 500 ms.

Tests (codex-interrupted-turn-terminals.test.ts) drive a real CodexAppServerAgentSession
against the scripted app-server in codex/test-utils/fake-app-server.ts: exactly the
interrupted turn's processes are terminated, by id, and `clean` is never sent; a turn
Codex starts before acknowledging the interrupt keeps its commands; the next `turn/start`
waits for the terminates; a command announced after the interrupt was accepted is
terminated once and the next turn waits for both sweeps, whichever answers first; a
completed command is forgotten and a failed one kept; only the latest sixteen accepted
interrupts are kept; a failing or unanswered terminate does not block the next turn. The
harness waits for the interrupted turn's `turn_canceled` before it starts the next turn,
as a caller does: notifications are handled asynchronously, so the interrupt's answer can
arrive before the turn has ended.

Fixes #7522


Claude-Session: https://claude.ai/code/session_01Ay568T2kmtotoh23Dtzi5K

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 19:58:12 +00:00
paseo-bot[bot] 04fe4be40f fix(claude): retain configured model metadata before a turn (#8465)
Rebuilding an idle session cleared its observed model and published null despite retaining an explicit model in its configuration. Fall back to that configuration until the next turn supplies an observed model.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 18:59:04 +00:00
paseo-bot[bot] 2d75cc80b2 test(server): cover routed permissions in one host journey (#8486)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 18:34:57 +00:00
paseo-bot[bot]andDominic Anaeto bfac132920 Stop Git polling while workspace folders are missing (#8462)
* fix(server): stop polling git for a workspace whose folder is gone

When a workspace's folder disappears together with its project (the
repository deleted, a volume unmounted), reconciliation leaves the
workspace registered, and the daemon kept polling it: a failed git
command and a warning about once a minute, and a working-tree watcher
retry every minute or two, for as long as the daemon ran.

The degraded poll now checks that the workspace folder exists before
refreshing. A workspace whose folder is gone is suspended once: it is
detached from its repository and working-tree targets, its timers stop,
and one warning is logged. A worktree that shared a repository target
hands the repository's polling and background fetch to a surviving
worktree. Nothing is archived. A working-tree watch that an open diff
still holds skips its consumer notifications and watcher recovery while
its folder is missing.

While suspended, the workspace runs no git. A stat every 60 seconds, a
new subscription, a forced snapshot or a refresh request checks whether
the folder is back; when it is, the workspace reloads its git facts,
refreshes, and rebuilds its observation.

Fixes #7856

* fix(server): keep missing workspaces suspended during refresh

Admit Git refreshes only after the folder has returned. Cover missing-folder polling, explicit refreshes, and restoration with real Git and the Linux observer.

Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>

* fix(server): preserve workspace snapshots through suspension

Drop queued refreshes and withhold publication when a folder disappears during an active read. Wait for that read before restoring observation so its stale result cannot overwrite the recovered snapshot.

---------

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 18:02:26 +00:00
paseo-bot[bot]andDominic Anaeto 34f996b32a Preserve pending questions and approvals after peer messages (#8453)
* fix(server): keep a recipient's pending permission when another agent messages it

A message from another agent (send_agent_message with sourceAgentId) was
enqueued with clearPendingPermissions: true, so it superseded the
recipient's pending permission request and the request was denied before
a human saw it. Agent-sourced messages now leave pending permissions
alone. Typed messages and sourceless `paseo send` still clear them.

Fixes #7602

* test(server): verify peer messages preserve answerable questions

Exercise message delivery through the daemon and provider interfaces so the regression checks that the question survives and its answer reaches the provider. Retain the human-steer cancellation behavior.

Co-authored-by: Dominic Anaeto <dominic.anaeto@gmail.com>

* test(terminal): make runtime copy fixture independent of umask

Set the source helper permissions after creation so the copy test measures preservation instead of inheriting the shell file-creation mask. The existing test fails under umask 077 without this setup correction.

Fixes #8175

---------

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 17:11:42 +00:00
3e83f433da Import large Claude sessions without exceeding the string limit (#8457)
* fix(claude): read the session rename from the end of a large transcript

Importing a Claude session read the whole transcript into one UTF-8 string to
look for its `custom-title` record, so a transcript past V8's maximum string
length failed the import with `RangeError: Invalid string length` before the
incremental history reader ever ran. The scan now reads the file backwards a
chunk at a time, which keeps the original intent of not walking the transcript
and never holds it as one string. Records without the needle are not decoded, so
a transcript with no rename costs a byte search per chunk.

Closes #8451

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

* test(app): wait for send readiness in composer recall

The previous prompt can appear and clear its draft before the send acknowledgement arrives. Wait for Send to be enabled before pressing Enter so recall setup does not silently leave the next prompt unsent.

Co-authored-by: qwist1233-cpu <qwist1233@gmail.com>

* fix(claude): scan large transcript records once

Retain unfinished record chunks and assemble each record once instead of copying and rescanning a growing buffer on every backward read. Cover import of a large record after the last explicit rename.

---------

Co-authored-by: qwist1233-cpu <qwist1233@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 15:56:42 +00:00
paseo-bot[bot] 674530152e test(server): cover filename downloads in one workspace journey (#8475)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 15:31:08 +00:00
Dominic 919e44b319 fix(server): start configured plugins concurrently (#8427)
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
2026-11-01 12:59:34 +00:00
paseo-bot[bot] 4fe44038e3 test(server): check subdirectory diffs before and after commit (#8466)
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-11-01 12:35:50 +00:00
Dominic 9b0542d127 fix(server): retry a connected host that failed the capability check (#8423)
* 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.
2026-11-01 10:59:33 +00:00
Dominic 8130147426 fix(app): stop the terminal from typing its version reply into the shell (#8419)
The browser terminal is a renderer and leaves protocol replies to the
daemon, but it still answered XTVERSION (CSI > q) and DECRQSS
(DCS $ q ... ST). Those replies went out through onData as if the user
had typed them, so a query from a program in the shell left text like
">|xterm.js(6.1.0-beta.292)" on the next input line. Both queries are
now swallowed with the other protocol queries.

Fixes #8111
2026-11-01 10:04:25 +00:00
Mohamed Boudra fa89738e3a chore(desktop): upgrade packaging tool and remove signing backport (#8450)
* chore(desktop): upgrade packaging tool and remove signing backport

* fix(nix): resolve the desktop workspace packaging tool
2026-11-01 14:46:52 +07: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
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
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