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>
* Add missing monochrome provider icons (kiro, devin, hermes, minimax-code, traecli, grok, deepseek-tui)
* fix(app): add Kiro catalog icon and Antigravity builtin icon
The ACP catalog's kiro entry had iconId null and no vendored svg, and
the native Antigravity provider resolved to the Bot fallback before the
daemon snapshot arrived. Vendor the Kiro brand mark, wire iconId, and
register a builtin AntigravityIcon matching the plugin's theme-aware
icon.svg.
* fix(app): keep Kiro eyes in monochrome icon
* test(providers): cover catalog artwork and snapshot-free icons
Lock down the missing provider marks through the catalog and the shared icon hook. Exercise the rendered catalog artwork in Chromium alongside coverage for the pre-snapshot fallback.
Co-authored-by: kevenhu001-cyber <keven.hu001@gmail.com>
Co-authored-by: Lu <jack1125516912@outlook.com>
* fix(website): preserve unrelated agent directory artwork
Drop the unrelated website mark introduced with the provider artwork. Cover the existing directory fallback and retained provider mark in a browser regression.
---------
Co-authored-by: kevenhu001-cyber <keven.hu001@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Lu <jack1125516912@outlook.com>
* fix(app): wrap sidebar empty-state actions so longer labels stay inside the card
The "Add project" / "Import session" row in the sidebar's empty state is a
non-wrapping flex row. With longer translations (e.g. Russian) the second
button overflows the card at the default 320px sidebar width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(app): cover sidebar empty-state actions staying inside the card
Renders the empty state in a real browser at the default sidebar width and
checks both actions' bounds against the card, for Russian (fails without the
wrap) and English.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(app): keep long sidebar actions inside narrow cards
Wrapping the row still lets a single translated action exceed its available width. Bound each empty-state action to the row and allow its label to shrink and wrap.
Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru>
---------
Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
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>
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.
Grouped sidebar projects chose the first eligible host even while a workspace on another host was active. Prefer that active host when online and eligible, keeping the existing fallback for other placements.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Michael Whitman <michael.whitman@getsteward.ai>
* fix(app): report offline hosts in new agent drafts
A disconnected client still exists, and pending form resolution and retained loading catalogs outlive the connection. Use host connection state for draft readiness and model loading while keeping known models available for reconnect.
Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
* test(app): confirm draft recovery on a fresh host connection
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
* fix(scripts): recover installs when a dependency patch changed
patch-package cannot apply a patch over a package patched with an earlier
version of it, and without --error-on-fail it exits 0 locally. Checkouts kept
the stale patch silently: the Markdown code block spacing fix never reached
them. The script now fails the install and removes that package so the next
npm install reinstalls it clean with the current patch. A patch-package that
cannot start fails the install without removing anything.
* fix(app): give Markdown blocks one gap and roomier desktop spacing
Every Markdown block is followed by one gap, density.blockGap: 12 on compact
layouts and 16 wider. The library's element styles and the views stacked
outside it (Mermaid segments on native, streaming head and tail) take the same
token, so no block type carries its own margins. Desktop was too tight at 12.
Markdown images show a zoom-in cursor on web, since tapping opens the lightbox.
Weights derived from the Playwright step minutes of five eight-shard runs; shard 8 drops from about 16 minutes to 10 and the shards sit within about 4 minutes of each other once normalized for runner CPU.
Keep drag widths out of the shared stylesheet and skip unchanged panes during width previews. Preserve the existing resize state and persistence behavior.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Ivan Malison <1246619+colonelpanic8@users.noreply.github.com>
* feat(app): rank, highlight, and timestamp Command Center results
Workspace and agent rows now show when they were last active, rank by
match quality and then recency, mark the query terms in every result
kind, and lead workspaces with their project icon.
Ties used to be broken by where the match landed in the string, so
"Deliver sidebar usage" beat "expose usage data" on sentence position
and recency almost never decided anything. Built-in rows now compare
only which fields matched and the matcher tier, then the most recent
row wins. The empty query follows the same rule, so it lists the most
recent workspaces and agents instead of alphabetical workspaces and
status-first agents.
Row and section heights live in list-metrics: a layout picks one row
inset and every height derives from it plus shared line boxes, which
the styles also read. The layout is chosen once at the top, so rows
never branch on it, and two-line rows are now vertically centered.
Desktop is denser (32/46); compact keeps 44pt touch rows (44/58).
findHighlightRanges takes the matcher's options so the marks match
what the list matched: the Command Center is not typo-tolerant, the
history list is.
* fix(app): keep the project icon out of Command Center row names
The fallback project icon draws the project's initial as text, which
became the first word of the row's accessible name ("C Command Center
..."), so screen readers announced it. The icon is decorative.
The scroll spec now reads the newest seeded workspace: the empty query
lists the most recent workspaces, so the first one seeded is no longer
among them.
Paseo subagent rows in the subagents list had an empty info strip: the row
only rendered the daemon-provided subtitle, which only provider subagents
carry. The row now uses the same facts line an agent's sheet shows when it
opens without its composer, so both surfaces resolve model, thinking, mode,
and context the way the composer's controls do.
The facts sit under the title instead of beside it, so a long task name
keeps the row's width instead of fighting the strip for it.
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.
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.
Two causes, both reproduced on a clone of a real long thinking-partner chat
(replies and thinking rows several screens tall, GFM tables).
1. The window lowered in e42771970 (initial 2 / batch 2 / window 5) holds only
two or three tall rows, so a fling outruns the mounted range and the viewport
crosses unmounted rows: 65 blank frames over a 4,152-frame traversal. Keep the
small initial render that bounds cold-open measurement, but refill a window of
10 in batches of 10: 0 blank frames over 4,347, p95 25 ms.
2. Scroll-to-bottom from deep history animated across every row in between,
which no finite window can mount in time: 9 blank frames (~150 ms) per jump.
Animate only when the current offset is within the bottom-side overscan,
otherwise jump instantly. Near-bottom jumps still animate. Web already does
not animate this jump.
Cold open on the same chat is unchanged (first content 569 -> 568 ms); the
deeper window costs first-scroll acknowledgement (2.58 -> 2.94 s in a debug
build).
* fix(markdown): restore link hover underline and code block spacing on web
The web renderer swap dropped both. Links: the library styles anchors
inline with text-decoration: none, so the link renderer has to track hover
itself; a stylesheet :hover rule cannot win. Spacing: the patched
renderers.codeBlock override returned the custom block bare, so it lost
the library's codeBlock margins and whatever followed sat flush against
it. The override now keeps those margins, including the zeroed trailing
margin of the last block, so web and native share one spacing config.
* test(desktop): expect Find to return focus to the chat viewport
#7263 moved focus on closing Find from the no-drag focus scope to the
scroll viewport so Page Up and Page Down keep working. The viewport emits
no window region by design (#5233), so the old assertion that the focused
element is no-drag failed on every run. Assert the new focus target and
re-check that the titlebar still has no drag exclusions.
* 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.
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>
* 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>
Closing Find focused its non-scrolling wrapper, leaving Page Up and Page Down unable to move the feed. Return focus through the viewport handle while preserving the reading position.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Include the leading cell when a selection starts on a wide character continuation, matching the native renderer highlight. Keep continuation cells out of copied text so real spaces remain unchanged.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
A catch-up projection could replace the live reply while leaving its cached prefix in the committed rows. Completion then discarded the complete reply as a duplicate. Reconcile the covered cached prefix together with the live reply.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(terminal): preserve Korean text when copying native terminal cells
* fix(terminal): omit continuation cells from copied text
Native terminal buffers already retain authoritative cell widths. Skip zero-width continuation cells when serializing a selection so Korean text copies with only its real spaces, while preserving the buffer representation.
Co-authored-by: helloimdevman <333048235+helloimdevman@users.noreply.github.com>
---------
Co-authored-by: helloimdevman <333048235+helloimdevman@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): find text in rows a timeline plugin draws
Chat find located a replaced message by its source id but counted matches
only inside elements marked as message text, which a plugin renderer never
sets, so a replaced prompt or reply reported no matches. Mark plugin rows and
search the whole row, with each view bounding a match.
* docs(plugins): qualify search in replacement timeline rows
Chat find discovers source-message matches before inspecting a replacement renderer. Document that renderer-added text is not independently indexed.
Co-authored-by: a-grasso <antonino.grasso@device-insight.com>
* fix(app): find visible text within contiguous plugin blocks
A whole-row walk counted closed popover text and reunited text before and after nested blocks. Keep consecutive block groups and exclude plugin text the browser is not drawing.
---------
Co-authored-by: a-grasso <antonino.grasso@device-insight.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): restore inline-code file path links
Classify complete inline-code spans with the file-link classifier before adapting them to the Markdown engine recognition pattern. Keep bare-text heuristics separate so route punctuation and line fragments work without adding prose false positives.
* perf(app): avoid parsing inline-link source on every reveal
Collect candidate values between equal-length backtick runs and let the Markdown engine own code boundaries. This preserves classifier decisions without reparsing long fenced blocks in JavaScript during streaming.
* fix(app): keep the compact sidebar close button beside the first nav row
The close button was absolutely positioned over the nav group, so it covered
the first row's label and hover fill. It now shares a flex row with the first
item, which shrinks to make room, and uses the compact header's icon button so
it gets the same size and round press highlight.
* test(app): cover the compact sidebar close button beside the first nav row
* Redesign the compact New workspace form as full-width field triggers
Each compact field is one full-width trigger with its label inside, above the
value, so the whole field is the tap target and presses highlight. The stack
stays anchored on the composer with Isolation and Branch rows reserved, so
nothing shifts as they come and go. Import session moves into the compact
header, and the title is gone; the fields name themselves.
The form's presentational code moves out of new-workspace-screen.tsx into
screens/new-workspace/form, where desktop badges and compact fields share one
FieldTrigger.
* Restore the desktop badge pressed colour
Main pressed badges to surface0; the field-trigger extraction folded it into the surface2 hover state.
* Use base text size for compact field values
docs/design.md sets interface text at fontSize.base; hierarchy comes from the muted label above.
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>
An image alone on its line, inside a paragraph with other lines, rendered inline
on iOS and web: the library only treats sole-child paragraph images as blocks,
and with hardSoftBreaks every newline is a break node. The source adaptation now
gives such images their own paragraph (keeping quote markers and list
indentation), so all platforms render them as blocks with image margins. Images
sharing a line with text stay inline. Verified through the library's md4c wasm
parser in the renderer tests.
* 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>
Authored Markdown destinations were filtered by the filename heuristics intended for inferred text, silently ignoring screenshot links. Resolve explicit destinations directly through the existing workspace opener so reads and failures reach the file pane.
Preview links bypassed the directory-aware opener and opened folder destinations as file tabs. Use the existing opener and explorer reveal actions, retaining preferred file placement and canceling pending checks when leaving the source tab.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Explicit Markdown hrefs were rejected by the filename heuristic used for inferred text. Let authored nested paths resolve without a recognized extension while preserving inline-code, automatic-link, and domain handling.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
The compact composer used a hardcoded box shadow shared by both themes,
so it read as a heavy band on light backgrounds. It now uses the shared
sm shadow token, whose light value is raised from 0.02 to 0.08 opacity
so the lift stays visible. Dark sm is unchanged.
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.
* Wait for plugin reload completion instead of the request deadline
The daemon answers plugin.reload.request only once the plugin is running
again or has failed, and a reload queues behind other plugin lifecycle
work such as an install with a preparation command. The shared client
applied its sixty-second session RPC deadline to that request, so a slow
reload failed with "Timeout waiting for message" while the daemon kept
loading the plugin, inviting a reload the daemon was still running.
Reload now waits for the daemon's own answer. Enable and disable keep the
session deadline, and a real startup failure still reaches the caller.
* Cover a slow plugin reload end to end
The CLI fixture now holds its own git build on a gate file, starts a
reload of an installed plugin behind that queued install, observes the
reload request at the proxy, keeps the gate closed past the client's
former one-minute deadline, and then asserts the reload's real result:
CLI exit 0, the plugin running, and exactly one reactivation. Listing the
plugin during the wait stays readable and does not restart it. A plugin
that cannot start still fails its reload with the daemon's error.
The request proxy that recorded install sources becomes a small observer
that records any session request, so the wait is measured from the
request boundary rather than from process start.
Verified: npx tsx packages/cli/tests/e2e/plugin-lifecycle.test.ts exits 0
in 135 s; the same fixture without the new scenario takes 66 s.
* Document how a reload reports its result
The CLI docs now say `paseo plugin reload` waits for the daemon to stop
and start the plugin, that cancelling the command or losing the
connection does not stop the daemon's work, and that `plugin ls` shows
the previous state until the reload finishes.
The plugin reference records the lifecycle fact behind it: a reload
queues behind the daemon's other plugin work, the daemon answers when
the plugin is running again or has failed, and status reads, Settings and
the logs are not the reload's outcome.
* Cover the Settings reload wait end to end
Adds a browser scenario for the ticket's user-facing half: with a gated
git install holding the daemon's plugin lifecycle queue, the row's Reload
goes out, the test keeps the gate closed past sixty seconds, asserts the
row stays pending with no error feedback, then releases the build and
asserts the daemon's plugin.reload.response and the app's "Reloaded
e2e-plugin" result.
The scenario turns plugins on through the daemon instead of the global
switch, whose transient "Plugins enabled" confirmation is not its
subject. The wait is measured from the reload request frame, which is an
outbound frame, not from the response stream.
Verified: npx playwright test --project=browser
e2e/browser/plugin-management.spec.ts -g "keeps Reload pending past a
minute" -> 1 passed (1.5m); plugin-reload-pending.png,
plugin-reload-past-deadline.png and plugin-reload-completed.png show the
pending row, the surface past the former deadline with no error, and the
finished reload.
* Correct the status guidance for a cancelled reload
Review finding: the note said a listing keeps the plugin's previous
state until the reload finishes, but that only holds while the reload is
still queued. Once it executes, the daemon removes the plugin from the
runtime catalog before stopping it (plugins/runtime.ts:377-382) and
resolvePluginStatus maps an enabled plugin that is not running to
"failed" (plugins/index.ts:71-78), so a listing read in that window
shows failed for a healthy reload.
Both passages now separate the two windows and say that neither a
listing nor the logs report the outcome of the outstanding reload.
The interim "failed" itself is TUC-1401.
* Harden the reload coverage against failures and lost connections
Review findings folded into the tests:
The Settings scenario releases its gated build in a finally block. Before
this, a failing assertion left the build polling forever, the daemon's
plugin lifecycle queue stayed blocked, and the fixture teardown's own
removePlugin timed out behind it. It also asserts the row's actions are
enabled again once the reload settles, next to the result feedback.
The connection-close regression now reconnects and asserts nothing
resends the lost reload; the no-replay invariant already covered for
legacy requests now holds for a pending reload too.
Verified: npx vitest run packages/client/src/daemon-client.test.ts -> 161
passed. npx playwright test --project=browser
e2e/browser/plugin-management.spec.ts -g "keeps Reload pending past a
minute" -> 1 passed (1.4m).
* Let the gated build finish before its files go
Review finding on packages/cli/tests/e2e/plugin-lifecycle.test.ts:450:
the finally block released the gate and deleted the gate directory
without waiting for the install and the reload it had started. The build
polls for the gate file, so cleanup could delete the release before the
child saw it and leave the build waiting until daemon shutdown.
The fixture now keeps both promises, releases the gate, and awaits them
before deleting their files.
Verified: npx tsx packages/cli/tests/e2e/plugin-lifecycle.test.ts -> exit
0, 161 s.
* Read the reload scenario as intent, not transport code
Review finding: the new browser scenario kept frame parsing, selectors,
polling, deadline arithmetic, screenshots and gate cleanup in one body.
docs/testing.md asks for complex setup in reusable helpers.
The wire observation, the gated queue hold, the row-state assertions, the
deadline wait and the surface captures are helpers now, and the body
reads as the flow: open Settings, hold the queue, reload, still pending
past the deadline, release, read the daemon's result.
Verified: npx playwright test --project=browser
e2e/browser/plugin-management.spec.ts -g "keeps Reload pending past a
minute" -> 1 passed (1.4m).
* Keep the reload lifecycle fact in one document
Review finding: the cli.md paragraph repeated the queue and interim-state
explanation that the plugin reference already owns. CLAUDE.md: "One fact,
one doc. Every other mention is a link."
The reference keeps the full explanation; the CLI page states what the
command does and links there.
* Release the gated build when its setup fails
Review finding: holdPluginLifecycleQueue started the install, then
waited up to 30 seconds for the build's started marker. A preparation
that took longer made the helper throw before it returned its cleanup
handle and before the test entered its try block, so nothing wrote the
release file: the build polled forever, the daemon's plugin lifecycle
queue stayed blocked, and the fixture's own removePlugin timed out
behind it.
The helper now owns that failure path: it releases the gate and drains
the install before rethrowing, so a queue it hands out is always
settleable.
Verified on Linux (Chromium, Playwright):
- With the started marker suppressed in a temporary local patch, the run
fails at the 30-second marker wait inside the helper and the teardown
still completes (both attempts ~33 seconds, no removePlugin request
timeout).
- With the marker in place, the scenario passes: 1 passed (1.4m).
* Keep an early install failure out of the unhandled path
Review finding: the marker wait in holdPluginLifecycleQueue ran before
the install promise had a rejection handler, so a preparation that failed
or a connection that closed before the build wrote its marker surfaced as
an unhandled rejection, which fails the run before the helper's own catch
can drain the queue.
The helper attaches a handler the moment the install starts and races the
marker wait against the install, so an early failure reaches the caller
as the daemon's own error, a build that never writes its marker still
fails as a 30-second marker timeout, and every path releases the gate and
drains the install.
Verified on Linux (Chromium, Playwright), patching the build command
locally for each failure branch:
- Early failure (build exits 1): fails in 4.2 s with the daemon's
DaemonRpcError for plugin.source.install.request, no unhandled
rejection, teardown completes.
- No marker (build waits for the gate): fails at the 30-second marker
wait, no unhandled rejection, teardown completes with no removePlugin
request timeout.
- Unpatched: 1 passed (1.5m).
* Keep a failed launch from ending the run before its cleanup
* fix(app): open folders from inline path links in the file explorer
Clicking a folder path in an assistant message opened a file tab that
failed with "Requested path is not a file". Extension-less
workspace-relative paths without a line number are now probed with a
directory listing before opening: directories open the Files explorer
navigated to that folder, everything else opens as a file like before.
Lexical directories (trailing slash, workspace root) now navigate the
explorer to the folder instead of only preloading its listing.
* fix(app): reveal linked folders and their contents
Resolve workspace folder links from directory metadata and expand their ancestor paths in Files. Preserve file and line-reference opening, including extensionless files.
Co-authored-by: Moy <moyfoxther@gmail.com>
* fix(app): cancel stale path opens and reveal hidden folders
Keep pending directory checks inside the path-opening model so a later click or navigation supersedes them. Explicitly revealing a hidden directory also enables the existing hidden-file visibility preference.
---------
Co-authored-by: Moy <moyfoxther@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* 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>
* fix(android): preserve dictation across audio interruptions
Playback focus loss does not mean microphone capture is unavailable. Keep dictation alive across media takeovers and wait for Android input silencing to clear, while preserving conversation interruption protection.
* test(android): verify dictation clears its selected audio route
* fix(app): make home actions reachable on short screens
Keep the home cards and community links in one scrollable flow so overflow stays reachable and the footer cannot overlap the cards.
* fix(app): keep home scrolling clear of window drag regions