Commit Graph
2480 Commits
Author SHA1 Message Date
paseo-bot[bot] ab6cdb7c89 fix(claude): return to Auto when approving a plan (#7453)
Offer Auto the same explicit resume action as Bypass and apply the saved mode before releasing plan approval. Ordinary Implement keeps selecting Accept File Edits.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-20 03:57:25 +02:00
paseo-bot[bot]andgszep 91154ba4e8 fix(opencode): advertise agent-scoped bridge tool schemas (#7383)
Co-authored-by: gszep <contact@gszep.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 16:58:21 +02:00
paseo-bot[bot] 05920a236c test(codex): observe permission events in auto-review scenarios (#7382)
List snapshots do not subscribe modern clients to permission events. Activate that feed before both scenarios so the request assertion and auto-review absence assertion exercise delivery.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 15:49:47 +02:00
paseo-bot[bot] dd244c076d fix(pi): remove running rows for refused subagent resumes (#7369)
A text-only refusal finishes successfully without identifying a child. Remove its provisional subagent row when the tool completes, while retaining the refusal in the tool timeline.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 14:11:41 +02:00
Mohamed Boudra 1c8c68f93e Keep workspace setup logs scoped to the visible setup panel (#7407)
* fix(workspaces): observe setup output only in the visible setup panel

Setup logs were requested for the whole session, including unrelated workspaces. Use directory status for discovery and source-owned workspace observations for details, preserving legacy delivery only for clients without the negotiated capability.

* fix(workspaces): publish external setup progress once per daemon

MCP and scheduled setup enter through the broadcast API. Publish them to the shared setup owner before session fanout so each observation gets one update and snapshots survive periods without connected clients. Keep the setup action available on older hosts to explain the required host update.

* fix(app): replace setup details with each observation snapshot

A host restart can return an empty setup snapshot. Apply that authoritative snapshot so an open panel does not retain output from the previous daemon. Assert setup membership requests as well as delivery in the browser lifecycle regression.

* test(workspaces): cover setup status catch-up after directory release

* test(workspaces): synchronize setup output and release fixture resources
2026-10-19 18:34:53 +07:00
Mohamed Boudra b6dde61a7f feat(plugins): accept inline SVG and component icons (#7368)
Every contribution `icon` now takes a Lucide name, `{ svg }`, or a
component. Attachment sources take only the first two because composer
drafts persist the source icon.

The daemon's provider-icon check and the app's inline-SVG check are the
same function in the shared SDK root, so a plugin sees the same reasons
in both places. The app parses each icon once at registration and fails
the plugin with that reason. Rendering goes through one module that
turns any form into a component, so surfaces never branch on the form.
2026-10-19 15:36:04 +07:00
Mohamed Boudra cafe4b01c8 chore(release): cut 0.12.0 2026-10-19 08:45:41 +02:00
paseo-bot[bot] a0790e7527 fix(server): collect large file observer benchmark batches (#7349)
Startup inventories exceed the function argument limit when spread into push. Append each event individually in both benchmark collectors so large fixtures can reach their measurement summary.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 04:58:10 +02:00
paseo-bot[bot] be0378ce63 fix(usage): keep distinct Cursor accounts in separate cards (#7344)
Cursor discovery used one constant account key across all credential stores. Derive that key from the token subject in both discovery paths, and isolate unreadable identities by store, so host merging preserves each account while shared accounts still deduplicate.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 03:55:30 +02:00
paseo-bot[bot]andAling33 f0acc2c72b Send MCP terminal keys in the running program’s input mode (#7343)
* fix(server): 正确编码 MCP 终端按键

send_terminal_keys 会将方向键、导航键和多数修饰键组合当作普通文字输入。
复用协议层编码器,并从终端前导序列恢复输入模式,保留 literal 和未知文本的原样发送行为。

补充 MCP 入口回归与真实 PTY 字节验证;MCP 文件 197 项测试通过,
最终终端回归 44 项通过,服务端类型、Lint 和格式检查通过。

Fixes #7337

* fix(terminal): keep MCP keys in the running program input mode

The worker mirror refreshed its input preamble only on snapshot reads, so MCP arrows used normal mode after an unattached program enabled application cursor keys. Carry the authoritative preamble with streamed worker messages before notifying consumers.

Co-authored-by: Aling33 <3489986145@qq.com>

---------

Co-authored-by: Aling33 <3489986145@qq.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 01:53:55 +02:00
paseo-bot[bot]andHemanth 08853039fb fix(server): keep resumed goal turns visible and stoppable (#7339)
A Codex goal can start while thread/resume is still connecting, before the manager can subscribe. Retain those startup events until the first subscriber and apply them before registration returns, preserving run state and cancellation ownership.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Hemanth <git@soni.im>
2026-10-18 21:55:29 +02:00
paseo-bot[bot] aef7cc36a0 fix(server): connect to relays over high-latency networks (#7336)
The runtime default cancels a pending IPv4 connect before slow routes complete, then fails immediately on unreachable IPv6. Give each relay address five seconds within the existing ten-second handshake deadline, covering both control and data sockets.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-18 20:57:22 +02:00
paseo-bot[bot] fcda2f1cf0 fix(hub): reconnect after silent connection loss (#7315)
A network path can swallow close notifications while the Hub socket remains open locally. Probe it with protocol ping/pong frames and feed stale sockets into the existing reconnect path.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-18 17:00:13 +02:00
Mohamed Boudra f7a0e2cbea test(server): wait up to ten seconds for the OMP relaunch to register MCP tools (#7304)
The crash-relaunch test waited with vi.waitFor's default one second for a
fresh runtime and MCP child to come up. On the Windows runner with three
workers that took longer once in six runs and failed main. The assertions
are unchanged; only the budget for the relaunch is realistic now.
2026-10-18 21:11:14 +07:00
Mohamed Boudra cc748dfe12 chore(release): cut 0.12.0-beta.3 2026-10-18 12:47:46 +02:00
Mohamed Boudra a5c566f807 Make full CI finish sooner: eight browser shards, split Windows server job, cancel superseded runs (#7275)
Eight Playwright shards with two workers each, format/lint/relay/sdk combined into one routed quality job, Windows server integration in its own job, cancel-in-progress on every ref, one vitest start for the filtered integration files, no fan-in gate, and a deadline for the heap-bound directory search test that covers its 27,000-directory fixture on Windows.

First run on the Team plan: 19m48s from creation to last job with zero queue, all 21 jobs green, 224 runner-minutes. The same workflow under the old 20-job cap finished in 58 minutes with up to 40 minutes of queue per job.
2026-10-18 13:52:54 +07:00
Mohamed Boudra 9521ee9955 feat(app): label Paseo tool calls verb-first with their context (#7283)
Paseo tool rows put the variable part first ("QA messenger finished"), so
truncation hid the fixed part, and MCP calls showed only the humanized tool
name with no context. Every Paseo tool now has one catalog entry in
protocol/paseo-tool-presentation owning its fixed label, the input field
shown as context, and its detail layout. Agent-message events read
noun-first ("Agent finished" + sender) and use the Paseo icon; the app
ignored it before because the wire detail's legacy "bot" icon won.

Summaries are capped in code at 120 characters because prompts can be one
enormous line; the renderer is not trusted to clip them.

The activity curator behind `paseo logs` and get_agent_activity printed a
bare "[Agent message]" because the server tool-call type never declared the
agentMessage field the projection sets; it now prints the event, sender,
and body.
2026-10-18 13:10:09 +07:00
Mohamed Boudra cf62b00911 Keep last successful usage visible when refresh fails (#7246)
* fix(usage): retain last successful data when polls fail

Keep the latest poll outcome separate from its successful snapshot so errors remain visible without discarding known usage or advancing its freshness. Preserve attempt timestamps for response ordering and isolate retained values by scoped login set.

* fix(usage): preserve history through discovery failures

A failed account-store read does not confirm that an account was removed. Retain its existing host mapping until successful discovery replaces it, without carrying mappings across agent launch environments.
2026-10-18 11:06:31 +07:00
paseo-bot[bot]andSimone Primarosa efd6d95f91 fix(plugins): return unavailable when steering provider without prompt.steer capability (#7270)
Co-authored-by: Simone Primarosa <simone.primarosa@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-18 06:06:08 +02:00
paseo-bot[bot] 1a6a9fa8d0 fix(claude): keep background child action logs after the parent finishes (#7266)
Late child frames were discarded after the launching turn ended, and parent completion cleared accumulated child actions. Keep card updates attached to the launching turn and release child actions on task completion.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-18 05:02:33 +02:00
paseo-bot[bot] a7a21d91c2 Keep overlapping directory searches from exhausting the heap (#7265)
* fix(server): keep overlapping directory searches within their scan budget

Construct child paths and branch iterators as the round-robin walk consumes them. Eager sibling expansion retained hundreds of thousands of unvisited children per search and exhausted the heap when requests overlapped.

* test(server): stop directory-search children before fixture cleanup

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-18 03:52:15 +02:00
Mohamed Boudra c517d07d6f chore(release): cut 0.12.0-beta.2 2026-10-17 20:07:37 +02:00
paseo-bot[bot]andKiraPC 86ab49153a Let Copilot implement plans after selecting Allow All (#7234)
Selecting Allow All now moves Copilot to Agent mode before enabling allow_all, so a session that was in Plan can implement the plan.

Closes #3855.

Co-authored-by: KiraPC <pasqualecarmine.carbone@gmail.com>
2026-10-17 16:54:51 +02:00
Derick WellsandMohamed Boudra f22775a8e1 Default agent-to-agent messages to steering in CLI and MCP (#5164)
* Let agents steer a running turn from send_agent_prompt and paseo send

When an agent used the send_agent_prompt MCP tool on a target that was
mid-turn, sendPromptToAgent ran without activeTurnBehavior, so the
prompt path fell through to replaceAgentRun. That cancelled the target's
active turn and every provider subagent it had in flight. The web UI,
child finish notifications and schedules already pass "steer"; the MCP
tool and the CLI had no way to ask for it.

Add an optional activeTurnBehavior input to send_agent_prompt. It
defaults to "steer" for agent-scoped callers and to "interrupt" for
top-level callers, so existing top-level behaviour is unchanged. Add
--steer to paseo send. Document both and cover them with tests.

* fix(agents): retain finish notifications during steering acknowledgement

Observe completion before dispatch and hold delivery until acceptance. A replacement discards the displaced turn observation and starts a fresh listener before its iterator runs.

* fix(agents): preserve notification ownership when follow-ups fail

Keep the previous observation until dispatch succeeds and suppress duplicate delivery during acknowledgement. Decide whether to retain the running turn from the dispatch result, including side commands requested with interrupt.

* fix(agents): deduplicate notifications across overlapping follow-ups

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-10-17 20:39:05 +07:00
sulthan zahran 1b450e487e fix(claude): don't treat a wrapper command's --version output as Claude Code's version (#7209)
resolveClaudeCodeVersion() probes <configured command> --version and parsed any output with the generic fallback in parseClaudeCodeVersion. With a wrapper command (e.g. cux), that output is the wrapper's own version, which then failed every minimumClaudeCodeVersion gate and silently hid Opus 5.5, Opus 5, Fable 5, Sonnet 5.5 and Haiku 5.5. Only trust output that identifies itself as Claude Code (x.y.z (Claude Code)); anything else falls into the existing unknown-version path that does not gate models.
2026-10-17 11:51:24 +02:00
paseo-bot[bot]andFelipe Fidelix 30799fda19 Return actionable errors to OpenCode agents for invalid tool calls (#7183)
* fix(server): return actionable OpenCode bridge errors

* fix(server): surface OpenCode tool input errors

* fix(server): surface OpenCode v2 tool errors

* test(server): cover OpenCode v2 bridge errors

* fix(server): classify missing schedules as tool input

* fix(server): surface schedule state conflicts

* fix(server): validate schedule tool inputs

* fix(server): keep tool contracts while reporting OpenCode input errors

Preserve the removal of create_agent.background and keep legacy schedule fields hidden. Verify client errors through the real bridge, catalog, and schedule service rather than mocked schedule failures.

Co-authored-by: Felipe Fidelix <felipe@fdx.is>

* fix(server): distinguish caller errors from stored data failures

Tag validation failures where tool arguments are parsed, so schema errors from persisted state remain internal failures. Preserve the missing-agent error at its producer and translate it for prompt delivery. Real HTTP regressions fail for both misclassifications before this change.

* fix(server): preserve messages for unclassified tool failures

Keep existing error messages on HTTP 500 responses so agents can correct failed tool calls. Exercise missing workspaces through the real script service and bridge route.

* fix(server): preserve clearing schedule names with blank strings

---------

Co-authored-by: Felipe Fidelix <felipe@fdx.is>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-17 07:57:22 +02:00
paseo-bot[bot]andboeto f472c9d1f4 Correct workspace source parameters in the Paseo skill (#7188)
* docs(skills): align workspace source parameters

* docs(skills): clarify workspace source inputs

* test(skills): check workspace guidance against MCP inputs

Keep the bundled workspace guidance aligned with the tool schema agents receive, so removed source parameters do not remain in the instructions.

Co-authored-by: boeto <bo@eto.me>

---------

Co-authored-by: boeto <bo@eto.me>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-17 06:47:31 +02:00
paseo-bot[bot] 88a7aec1b8 fix(claude): keep active turns running through settings changes (#7179)
A pending thinking change retired the live query when mode, model, or command controls requested it. Reuse the query owned by the current turn and apply pending launch settings after the turn finishes.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-17 03:54:00 +02:00
paseo-bot[bot]andHung Le cd77ecd837 Start idle OMP agents when they receive follow-ups (#7169)
* fix(server): run slash commands sent by another agent out of band again

* fix(omp): send /steer and /follow-up as prompts so an idle agent starts a run

* test(omp): verify idle follow-ups and parent notifications

Cover real daemon and MCP delivery, and keep the fake runtime tests independent of an installed OMP executable.

Co-authored-by: Hung Le <22406703+nhthung@users.noreply.github.com>

* fix(omp): report idle follow-up admission failures

Use the existing prompt lifecycle for an idle command so acknowledgements and late rejections settle the child and notify its caller. Keep busy commands on the streaming prompt path, and accept one runtime prompt input object.

---------

Co-authored-by: Hung Le <22406703+nhthung@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-17 01:10:35 +02:00
paseo-bot[bot] 30122b1ae1 Show a background Claude subagent's action log on its card (#6242)
* fix(claude): show a background subagent's action log on its card

Claude Code answers a background Agent call at launch and streams the
child's frames afterwards. Since #6067 the sidechain tracker stopped
emitting the parent card once the call had its result, so the card's
log stayed empty. The tracker now rebuilds the card from the settled
call, keeping its status, output, and label, and adds the child's
action log.

Closes #6157

* fix(claude): release a settled subagent call when the child finishes

* fix(claude): keep a background subagent's card in the turn that settled it

A background child often keeps streaming after the parent's turn ends. Its
frames then rebuilt the settled card in the next turn with an empty log, and
the projection showed it as a second card for the same call. The settled call
now rebuilds the card only within the turn that answered it.

* test(claude): model the turn boundary in background card coverage

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-16 23:53:46 +02:00
xzthemeofsss d152f1529f fix(app): recover failed question responses (#7098)
* test: reproduce failed question response recovery

* fix: show question response failures and allow retry
2026-10-16 22:12:05 +02:00
Mohamed Boudra e2f4948f92 chore(release): cut 0.12.0-beta.1 2026-10-16 21:00:46 +02:00
Mohamed Boudra a8deb51086 fix(server): keep provider images separate from adjacent prose
Generated image Markdown was concatenated into the preceding paragraph and rendered at inline size. Preserve paragraph boundaries around image output while retaining intentional inline image behavior.
2026-10-16 17:23:43 +02:00
Jiawen Geng 64693f21cf fix(cursor): show plan usage in Cursor agents' context details (#6353)
Cursor agents never showed plan usage cards under their context details.
ACP sessions had no usageSession(), and the Cursor usage source only ran
global discovery, so per-agent discovery always came back empty.

Cursor ACP sessions now report a usage session (provider "cursor" plus
their launch env). The Cursor usage source resolves the cursor-agent
auth.json for that env. Sessions on CURSOR_API_KEY or CURSOR_AUTH_TOKEN,
the in-memory store, or the macOS Keychain (the default there) report
no login.
2026-10-16 16:56:39 +02:00
4117dce2d3 Fix local WAV transcription startup (#7103)
* fix(speech): complete local transcription providers

* test(speech): document lazy worker assumption

Co-authored-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com>

---------

Co-authored-by: LauraGPT <lauragpt@users.noreply.github.com>
Co-authored-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com>
2026-10-16 08:19:21 +02:00
f56c013928 Open configured terminals after worktree setup (#6999)
* fix(server): open worktree.terminals when a workspace is created on its own

runWorktreeSetupInBackground only opened the paseo.json worktree.terminals
when its caller passed runAutoTerminals, and only the fork-PR "allow setup"
handler did. workspace.create, the request the New Workspace screen sends,
ran worktree.setup and then skipped the terminals.

Both callers want the terminals, so the flag goes away: terminals follow a
successful setup on a newly created worktree. Reused worktrees stay excluded
by shouldBootstrap, and the agent setup continuation never reaches this
function, so nothing opens twice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): run automatic terminal regressions in CI

Include workspace creation in the existing integration command, and append to the terminal marker so repeated command execution fails the regression.

* test(server): make workspace fixtures portable on Windows

Run the setup fixture through a command accepted by PowerShell, await its readiness, and fix the fixture Git line-ending policy. Allow Windows directory locks to settle during cleanup.

* test(server): expose setup failures and await fixture cleanup

Check the public setup status before terminal startup so failures distinguish setup errors from terminal creation. Use asynchronous directory removal so Windows cleanup retries leave the event loop available.

* test(server): start the Windows setup service asynchronously

The Windows regression starts its service but setup stays running, so terminal bootstrap is never reached. Launch the fixture service explicitly with Start-Process and retain the readiness and setup-completion assertions.

---------

Co-authored-by: David Yang <9925+davidyang@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 23:11:13 +02:00
Mohamed Boudra 7aa3fac069 fix(providers): scope project-dependent model discovery to workspaces
Global discovery has no linked project. Initialize the bridge to check availability, but only open discovery sessions when a workspace is supplied.
2026-10-16 01:19:00 +07:00
paseo-bot[bot] d172d060a5 server: keep streamed OpenCode v2 chunks from holding their whole message (#6262)
Each streamed text or reasoning chunk was cut from the accumulated
message with slice, which can share the source string's storage. The
timeline store keeps every chunk, so a 128 KB reasoning part retained
about 128 MB: every chunk held the full message as it stood when the
chunk arrived. Long OpenCode v2 reasoning streams exhausted the daemon
worker's heap.

The timeline now emits an independent copy of each suffix, so retained
memory follows the length of the text.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 18:28:07 +02:00
Mohamed BoudraandOdin Glynn-Martin 16bb179e67 feat(providers): add opt-in Hoplite and searchable provider grid (#6953)
Preserve the bundled Hoplite ACP adapter and provisioning transformer, activate it only after Add, and provide a searchable provider grid. Restore the contributor's original icon without the copyright mark.

Co-authored-by: Odin Glynn-Martin <odin.glynn@icloud.com>
2026-10-15 21:25:23 +07:00
Mohamed Boudra e08389065c fix(plugins): allow protocol type imports without local dependencies (#7023)
Protocol contracts are available through the SDK peer dependency during development, but clean Git installs lack that dependency tree. Accept erased protocol type imports while retaining runtime dependency resolution and SDK ownership checks.
2026-10-15 21:13:00 +07:00
paseo-bot[bot]andGrant Ammons 80badb3b8f fix(opencode): answer multi-select v2 questions from the question card (#6149)
Closes #6135

Co-authored-by: Grant Ammons <grant@grant.dev>
2026-10-15 15:15:19 +02:00
71f575e16a Keep malformed Claude question answers retryable (#6936)
* fix: reject a question permission that would deliver no answer

Answering an `AskUserQuestion` permission in any shape but
`updatedInput.answers` keyed by one of its questions resolves as `allow` and
delivers nothing. The waiting agent is told "The user did not answer the
questions." — an affirmative falsehood rather than silence, so neither side can
see that anything failed. The responder sees success; the agent believes the
human declined and acts on that.

The field it is most natural to reach for cannot work. `selectedActionId` is
`z.string().optional()` with no membership check, and is read only for `plan`
kinds; a question advertises `actions: undefined`, so there is no action id to
name in the first place.

It is also unrecoverable. `respondToPermission` deletes the request from
`pendingPermissions` on entry, so the malformed answer consumes it and the retry
fails with "No pending permission request". The guard runs before that delete,
and `AgentManager` drops its own copy only once the call resolves, so both maps
survive the throw and the request stays answerable.

The answer contract is per provider, so the guard is in the Claude provider
rather than in `AgentManager`. Claude keeps an answer only when its key is a
question's full text or its header and its value is a non-empty string; Codex's
`mapCodexQuestionResponseByHeader` reads headers only and deliberately selects
each question's first option when nothing maps, which a shared guard would have
rejected; OpenCode reads headers only as well.

`resolveClaudeAskUserQuestionAnswers` is extracted from
`normalizeClaudeAskUserQuestionUpdatedInput` with no change in behaviour, and
both it and the guard now use it. So "would this deliver anything" is answered
by the code that does the delivering, rather than by a second copy of its rule —
which matters more than it looks, because that rule has two details easy to
restate wrongly: `readNonEmptyString` tests `value.trim()` for emptiness but
returns the *original* string, so a question named `" Which colour? "` is keyed
by that padding; and an empty `updatedInput.questions` array is a list that wins
over the request's own questions and maps nothing, not an absent one.

Verified on a live daemon over the MCP `respond_to_permission` path against a
seat whose question text is literally `" Which colour? "`: `selectedActionId`,
the trimmed key, an empty echoed question list and a numeric answer are each
rejected with the request still pending, and
`{"answers":{" Which colour? ":"Ochre"}}` then reaches the agent.

One known limit: the WebSocket path (`session.ts handleAgentPermissionResponse`)
catches the throw and emits an `activity_log` error rather than failing the
call, because a permission response is modelled as a notification. So
`paseo permit allow` still prints `allowed` and exits 0 for a rejected shape.
The destructive half is closed on every path — the request survives and the
agent is never told a falsehood — but closing the reporting half needs a
protocol change.

* test(claude): cover the question-answer-required retry path

A non-deliverable answer to an AskUserQuestion permission is rejected, but
the pending request survives it: a corrected retry against the same request
id is accepted, and the waiting agent receives the answer.

Mutation testing on a fork found that the existing suite does not pin this
ordering — moving the deliverability check to run after the request is
deleted from pendingPermissions still leaves every existing test green. This
test reds against that change.

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

---------

Co-authored-by: Thomas Van <minhthong@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: paseo-bot <paseo-bot@users.noreply.github.com>
2026-10-15 14:21:03 +02:00
paseo-bot[bot]andplatanus-kr 0708b8295c Preserve explicit Claude session names on import (#6930)
* fix(server): name an imported Claude agent after its /rename

Importing a Claude session named the agent after its first prompt even when the
session had been renamed in the CLI, so the name had to be set again by hand.
#4216 fixed the Import Session listing; the imported agent still kept the
prompt.

Read the last usable `custom-title` from the transcript and pass it as the
imported config title. The record is re-emitted on every save, so searching
backwards from the end of the file finds the current name without walking a
transcript that can reach tens of megabytes.

Only an explicit rename is carried over. Agents are named after their first
prompt line since #1563, so adopting the generated `ai-title` here would put
that LLM summary back.

Refs #2513

* refactor(server): drop unused generality from the Claude title reader

readLastClaudeTitle took content, type and field so it could read both
custom-title and ai-title records, which the listing needed before #4216 took
that over. Only the custom-title read is left, so the two extra parameters are
dead flexibility that also broke the single-object-parameter rule in
packages/server/CLAUDE.md.

Collapse it to readLastClaudeCustomTitle(content) and pull the record type into
a constant so the needle and the type check share one literal.

Hooks skipped: the repo-wide typecheck fails on two pre-existing Electron
typing errors in packages/desktop/src/main.ts that reproduce with this change
stashed. packages/server typecheck, lint and format all pass.

* test(server): drive the real resume path in the import title tests

The tests assigned an inline arrow function to client.resumeSession to keep
Claude Code from spawning. Importing replays the transcript from disk and never
starts a process, so the stub was never needed. Dropping it runs the real
resume path, which is what docs/testing.md asks for, and removes the arrow
assignment that docs/coding-standards.md rules out.

Hooks skipped: the repo-wide typecheck fails on two pre-existing Electron
typing errors in packages/desktop/src/main.ts that reproduce with this change
stashed. packages/server typecheck, lint, format and the 83 claude tests pass.

* fix(server): narrow the transcript read error instead of asserting it

The ENOENT check cast the caught value to NodeJS.ErrnoException to reach
`code`, which is the kind of assertion docs/coding-standards.md rules out:
narrow with `if`, do not silence the compiler. Add the same local type guard
pid-lock.ts already uses and test through it.

Behaviour is unchanged. A value that is not an Error still falls through to
the rethrow, exactly as reading `code` off the assertion did.

Hooks skipped: the repo-wide typecheck fails on two pre-existing Electron
typing errors in packages/desktop/src/main.ts that reproduce with this change
stashed. packages/server typecheck, lint, format and the 83 claude tests pass.

* fix(server): let claudeProjectDirSync resolve the Claude config dir

The import title reader built the config dir itself through os.homedir(),
but os is no longer imported here, so the fallback threw a ReferenceError
whenever CLAUDE_CONFIG_DIR was unset. claudeProjectDirSync already resolves
the same default.

* test(server): give the import title helpers object parameters

* fix(server): preserve imported session renames across history locations

The import title reader must use the same provider environment and transcript
lookup as history replay. Otherwise an imported session has its history but
loses its explicit name when its configuration directory or project changed.

Co-authored-by: platanus-kr <platanus.kr@gmail.com>

---------

Co-authored-by: platanus-kr <platanus.kr@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 13:17:01 +02:00
paseo-bot[bot]andbwestlund17 4d5c3c13d4 fix(acp): preserve slash command argument hints (#6920)
ACP command updates discarded input hints before the autocomplete command list reached consumers. Preserve the advertised hint, retaining the empty hint for commands without input metadata.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: bwestlund17 <brian.westlund@proton.me>
2026-10-15 12:13:18 +02:00
Mohamed Boudra d3efddb0b5 test(server): await provider discovery before readiness assertion (#6994)
Repeated snapshot reads supersede pending launch resolution and keep readiness loading. Await the refresh RPC before asserting the discovered state.
2026-10-15 15:35:14 +07:00
paseo-bot[bot]andAlexander Adam 0ed57187a9 Keep fork owners in Gitea and Forgejo checkout names (#6829)
* fix(gitea): prefix fork PR branches with the owner

Two forks with the same branch name (say patch-1) ended up on the same
local branch. The gitea service had no buildPrLocalBranchName or
defaultCheckoutRefs, github has both.

getPullRequestCheckoutTarget also fell back to refs/heads/<name> on
origin for fork PRs. Thats the base repo's branch, not the fork's, so
a failed refs/pull fetch checked out the wrong branch without an error.

fixes #3515

* refactor(forge): share fork branch naming with github

moved the owner normalizer and the branch name builder to
utils/change-request-checkout.ts, gitea and github both use it.

github changes a bit: a fork PR with an unknown or unusable owner (eg
deleted fork) now gets pr-N/<branch> instead of the bare branch name,
which could collide with a local branch the same way #3515 did.

* fix(gitea): PRs from a deleted fork are still cross repo

the API drops head.repo once the fork is gone, we read that as a same
repo PR and fetched refs/heads/<name> from origin

* fix(gitea): handle AGit PRs and deleted head branches

neither has a branch on origin. forgejo reports refs/pull/N/head as
head.ref for both, so skip the refs/heads fallback and dont track
origin.

also try refs/pull/N/head on upstream for clones where origin is your
fork, like github does. that list lives in the shared util now.

* test: resolver harness uses the real branch helper

plus deleted forks and same repo PRs without an origin branch

* fix(gitea): collapse pull-ref-only heads to pr-N in local branch names

buildForkLocalBranchName still used the raw headRef even when it was
just the pull ref (refs/pull/N/head), which agit prs and deleted head
branches report as their headRefName. that gave local branches literal
names like refs/heads/refs/pull/3/head.

* fix(gitea): surface hasHeadBranch on the pr checkout target

resolveForkCheckoutFacts already knew whether a pr had a real head
branch (agit flow, or head.ref == the pull ref both mean no). now that
signal reaches buildPrLocalBranchName so worktree names and local
branches stop being named after the raw pull ref.

covers same-repo, fork with owner known, and deleted fork all with no
real head branch. added an end to end gitea-service test plus resolver
cases since the worktree slug follows localBranchName too.

* refactor(forge): one head ref kind on the checkout target

hasOriginHeadBranch and hasHeadBranch could describe contradictory
states (cross-repo checkout claiming an origin head branch). collapse
both into headRefKind: "branch" | "pull-ref" and derive origin
tracking in the resolver instead of storing it separately.

Co-authored-by: Alexander Adam <alexander.adam@vade.io>

* fix(worktrees): avoid branch namespace conflicts in fork checkouts

Fork owner prefixes can name an existing branch as a parent, which Git rejects even when the full proposed name is unused. Allocate names against parent and child refs, suffixing the conflicting segment while preserving existing branches and fetched commits.

* test(worktrees): make fork fixture line endings deterministic

Windows Git converts the fixture checkout to CRLF when core.autocrlf is enabled. Set the repository fixture to preserve its written LF bytes so the content assertion checks the fetched patch on every platform. Reproduced the failure locally with inherited core.autocrlf=true and verified the corrected setup against that same configuration.

---------

Co-authored-by: Alexander Adam <alexander.adam@vade.io>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 10:10:54 +02:00
paseo-bot[bot] 4d8bed9ddd Keep Claude's context meter on the active model (#6814)
* fix(claude): keep context meter on the active model

Claude result modelUsage accumulates models across the session. Reading its largest window replaced Haiku capacity with a previous Opus window at turn completion. Select the runtime model entry and retain the seeded limit when that entry is absent or invalid.

* refactor(claude): name context fixture inputs and simplify result usage

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 09:13:13 +02:00
paseo-bot[bot]andhadan8977 b2ca7dcf03 Check generated IDs in the daemon upload test (#6810)
* test(server): stop expecting request-derived upload IDs

* test(server): check full uuid shape for upload id

* test(server): format generated upload ID assertion

Retain the contributor correction to the stale request-derived ID expectation while satisfying the repository formatter.

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-10-15 08:08:40 +02:00
paseo-bot[bot] 5c108f345c Preserve renames in committed file diffs (#6895)
* fix(git): preserve renames in committed file diffs

Follow the requested destination through rename detection so the patch agrees with commit history instead of showing the whole file as newly added.

* test(git): keep rename fixtures valid across platforms

* fix(git): keep added copies out of committed rename diffs

Detect rename sources across the first-parent commit before narrowing the patch. Follow mode also detected copies, causing added files to open as partial diffs against unchanged files.

* perf(git): share committed rename discovery across file requests

Opening a commit requests all of its file diffs concurrently. Share pending and completed rename scans for immutable commit IDs in a bounded cache, while symbolic refs always read fresh metadata.

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 07:05:42 +02:00
paseo-bot[bot] 8ff2424da1 Return checkout diff hunks from subdirectory workspaces (#6882)
* fix(git): return checkout diff hunks from subdirectory workspaces

Checkout paths are repository-relative, but one-shot diff reads used the workspace subdirectory for Git pathspecs. Resolve the worktree root once so patch selection and file reads use the same coordinates as the live subscription.

* test(server): await bounded discard fixture cleanup on Windows

The discard assertions pass but Windows can retain a directory lock during cleanup. Await asynchronous removal with bounded retries after daemon shutdown, preserving failure for persistent locks. Matches the verified cleanup correction in #6912 for #6918.

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 05:08:39 +02:00