buildClientConfig in test-daemon-connection.ts never set appVersion, so
probe clients (which become the live client) sent hello without it. The
daemon's version gate then hid Pi/Copilot from all these sessions.
Also update appVersion on the Session when a client reconnects with a
newer version, so stale sessions don't stay gated forever.
- Add classify.ts as the single source of truth for CLI invocation
routing (discriminated union, derives known commands from Commander)
- Remove all hardcoded command lists and duplicate path detection logic
- Simplify shell wrappers to dumb pipes (zero classification)
- Fix hot-start: use `open -n -g -a` (VS Code pattern) so second-instance
event fires when app is already running
- Fix cold-start race: pull-based IPC (getPendingOpenProject) so renderer
fetches the pending path after React mounts, instead of push event that
arrived before the listener existed
- Fix asar read corruption: unpack node-entrypoint-runner.js from asar
(Node.js v24 in Electron 41 can't parse package.json inside asar)
- Strip ELECTRON_RUN_AS_NODE from env when spawning desktop app from CLI
AgentProviderSchema was z.enum() which caused old clients to reject
session messages containing unknown providers (pi, copilot), breaking
the entire session. Changed to z.string() for future clients.
For currently deployed clients (<0.1.45), the daemon now filters out
unknown providers based on the appVersion sent in the WebSocket hello
message. Clients that don't send appVersion only see claude/codex/opencode.
* fix(app): reorder settings sections for better grouping
* feat(app): add setup hint and paseo.sh link on mobile welcome screen
New app store users land on the welcome screen with no context. Show a
brief explanation that the desktop app or server is needed, plus a link
to paseo.sh — only on mobile (iOS/Android), hidden on web/desktop.
* docs(release): add pre-release sanity check and clarify changelog scope
Add a Codex 5.4 review step before cutting releases to catch breaking
changes and backward-compatibility issues (mobile apps lag behind
desktop/daemon updates). Clarify that the changelog always covers the
delta from the previous stable release, not from the last RC.
* feat(server): add Pi agent provider and re-enable Copilot
Add Pi (pi.dev) as a new ACP-based agent provider with bundled pi-acp
adapter. Pi-acp reports thinking levels as ACP modes and bash tool calls
with kind "other", so the Pi provider uses generic ACP extension hooks
to remap these to the correct Paseo concepts:
- sessionResponseTransformer: remaps ACP modes → configOptions[thought_level]
- thinkingOptionWriter: writes thinking via setSessionMode instead of
set_config_option (which pi-acp doesn't support)
- toolSnapshotTransformer: remaps bash tool kind from "other" to "execute"
- modelTransformer: cleans slash-prefixed model labels
Also re-enables the Copilot provider (disabled since 44da0c67) and
removes the claude-acp provider.
* fix: update lockfile signatures and Nix hash
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix(server): deduplicate workspaces by resolving to git worktree root
Agents running in subdirectories of the same git repo were creating
separate workspace entries in the sidebar. Now workspace IDs resolve
to the git worktree root (via the already-computed `worktreeRoot` from
`inspectCheckoutContext`), so all agents in the same checkout share a
single workspace. Stale subdirectory workspace records are archived
during reconciliation.
* fix(server): fix 3 broken test files in server unit suite
- relay-reconnect: move speech mock to correct constructor position and
rename getSpeechReadiness→getReadiness after SpeechService refactor
- commands-poc: add credential/CLI availability guards matching
claude-agent.integration.test.ts pattern
- claude-sdk-behavior: pass pathToClaudeCodeExecutable via findExecutable
and add credential guards matching real provider configuration
* fix(server): fix race condition in loop-service test mock
Replace setTimeout(..., 0) with queueMicrotask() in ScriptedAgentSession
so turn_completed events fire before the verify check runs. Fixes flaky
CI failure where the file write hadn't completed before verification.
* fix(server): use /bin/sh for loop verify checks instead of /bin/zsh
More portable across CI environments. Also use queueMicrotask in test
mock to fix race condition between event emission and waiter setup.
* fix(server): correct import paths for isCommandAvailable and findExecutable
Import from utils/executable.js (where they're exported) instead of
provider-launch-config.js (which only imports them internally).
* fix(app): reorder settings sections for better grouping
* feat(app): add setup hint and paseo.sh link on mobile welcome screen
New app store users land on the welcome screen with no context. Show a
brief explanation that the desktop app or server is needed, plus a link
to paseo.sh — only on mobile (iOS/Android), hidden on web/desktop.
* docs(release): add pre-release sanity check and clarify changelog scope
Add a Codex 5.4 review step before cutting releases to catch breaking
changes and backward-compatibility issues (mobile apps lag behind
desktop/daemon updates). Clarify that the changelog always covers the
delta from the previous stable release, not from the last RC.
* feat(cli): support `paseo .` to open desktop app with project directory
Similar to VS Code's `code .`, users can now type `paseo .` or
`paseo <path>` to open the Paseo desktop app with that directory as
the active project.
- Desktop shims detect path-like first args and launch Electron in GUI
mode with --open-project instead of CLI passthrough mode
- Electron main process parses --open-project, sends IPC event to
renderer, and forwards via second-instance for the already-running case
- Renderer OpenProjectListener reuses existing openProject() RPC flow
- Standalone CLI discovers the desktop app per platform and spawns it
Introduce a generic feature system where providers declare dynamic
features (toggles/selects) and the app renders controls automatically.
One message pair (set_agent_feature_request/response) handles all
feature mutations. Feature values persist and restore on agent resume.
First consumer: Codex fast mode (service_tier) — gated to supported
model families, with proper cleanup on model switch.
Add a new Integrations section in desktop settings that lets users
install the Paseo CLI and orchestration skills directly from the app.
CLI install symlinks the bundled shim to ~/.local/bin and updates the
user's shell rc file if needed. Skills install copies SKILL.md files to
~/.agents/skills/, symlinks into ~/.claude/skills/ for Claude Code, and
copies to ~/.codex/skills/ for Codex. Both use a single status check
code path for install verification and on-load detection.
Also adds a /docs/skills page documenting all six orchestration skills,
extracts shared settings styles (section headers, rows) used across
the daemon, integrations, and shortcuts sections, and reorders the
settings sidebar to group integrations and daemon together.
Add paddingBottom to the content area equal to the header height so the
visual center accounts for the header above, keeping TitlebarDragRegion
scoped to the content area for Electron window dragging.
Unistyles' StyleSheet.create((theme) => ...) wraps styled components in
<UnistylesComponent> and patches native view properties via C++. When
these dynamic styles are applied to Reanimated's Animated.View, a theme
change causes both systems to fight over the same native node, crashing
with "Unable to find node on an unmounted component."
Fix: use plain React Native StyleSheet for static positioning on
Animated.View, and pass theme-dependent values (backgroundColor) as
inline styles from useUnistyles() instead of Unistyles dynamic sheets.
Also:
- Add gestureAnimatingRef to prevent double withTiming during gesture opens
- Remove all debug instrumentation added during investigation
- Add Maestro flow and bash script for automated theme-toggle verification
- Add docs/MOBILE_TESTING.md covering Maestro patterns, self-verification
loops, the Unistyles+Reanimated pitfall, and simulator commands
New app store users land on the welcome screen with no context. Show a
brief explanation that the desktop app or server is needed, plus a link
to paseo.sh — only on mobile (iOS/Android), hidden on web/desktop.
The Electron startup blocked on a ~2.6s synchronous CLI status check before
showing the app. Now the host runtime controllers (which probe persisted
connections) race against the bootstrap path — if the daemon is already
running, the UI comes online in milliseconds.
Also converts the desktop CLI spawn calls from spawnSync to async spawn
so the Electron main thread is no longer blocked during daemon status checks.
Remove the hardcoded mode whitelist so user-defined agents (from
opencode.json or global config) appear in the mode picker. Add a
listProviderModes API (client → session → provider) so the draft
agent form fetches dynamic modes instead of relying on the static
manifest. Fix slash command dispatch to accept optional arguments.
Closes#185
Stop auto-archiving workspaces when all their agents are archived —
only archive when the directory no longer exists on disk. This prevents
projects from disappearing when users archive their last agent.
Add a kebab dropdown menu to all project rows (desktop) with a
"Remove project" action that archives all workspaces in the project.
When the desktop app starts and finds a running daemon with a different
version, it now restarts it automatically. Only applies to daemons the
desktop app itself started, identified by a PASEO_DESKTOP_MANAGED flag
written into the PID lock file.
Also rewrites resolveStatus() to use the CLI daemon status command
instead of manually parsing the PID file, and surfaces daemonVersion
in the CLI status output from the WebSocket hello message.
The tab sync effect pruned archived agent tabs without checking if they
were pinned, so clicking an archived agent from the sessions page would
open and immediately close the tab.
On non-Mac platforms, Ctrl+C now copies selected text to clipboard
(falling through to SIGINT when nothing is selected) and Ctrl+V
pastes from clipboard into the terminal.
The scrollbar hook's raw DOM `input` listener on the textarea called
setState before React Native Web's delegated handler could process the
same event, causing a re-render with the stale controlled value and
swallowing the edit. Scroll and ResizeObserver already cover all
scrollbar metric updates.
Add a "Full status" button in the desktop daemon section that runs
`paseo daemon status` via Electron IPC and displays the raw output
in a modal.
Also fixes Commander.js argv parsing when the CLI is invoked via
Electron's ELECTRON_RUN_AS_NODE — Commander auto-detects the Electron
environment and skips only 1 argv element instead of 2, causing
"unknown command" errors. Fixed by explicitly passing { from: "node" }.
Check target, parentElement, and document.activeElement as focus
candidates instead of relying solely on the direct event target.
Fixes scope misdetection when the keyboard event target is a text
node or non-element.
* feat(server): add ACP base provider with Claude ACP integration
Implement a generic Agent Client Protocol (ACP) base provider that any
ACP-compatible agent can extend with minimal code. Includes a concrete
Claude ACP implementation via @agentclientprotocol/claude-agent-acp
with full parity to the existing Claude Code provider.
The base handles subprocess lifecycle, streaming translation, permission
bridging, terminal/fs callbacks, listModels, loadSession/resume, and
mode/model management. The concrete class only specifies the command,
modes, and availability check.
* fix: update lockfile signatures and Nix hash
* feat: add Copilot ACP provider, eliminate hardcoded provider unions, fix ACP streaming bugs
Add Copilot as an ACP provider (copilot --acp), with real modes and models
discovered from the ACP server. Fix two ACP base bugs: duplicate assistant
text (emit deltas not cumulative) and idle→running→stuck (fire-and-return
startTurn). Replace all hardcoded provider string unions with string/manifest-
derived values so adding a provider only requires: impl class, manifest entry,
registry factory, icon, and E2E config. Add provider docs and Copilot icon.
* fix: update lockfile signatures and Nix hash
* feat(app): add OpenCode provider icon
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Improve draft and live model selectors with search, favorites, and clearer provider context. Keep live agents honest by showing other provider catalogs as browse-only until provider switching exists.
Co-authored-by: David Longman <dlongman@tokentradegames.com>
On non-Mac platforms, let xterm.js ClipboardAddon handle Ctrl+C (copy
when text is selected) and Ctrl+V (paste) instead of sending control
codes to the PTY.
Closes#175
Add useWebElementScrollbar (for DOM elements) and useWebScrollViewScrollbar
(for RN ScrollView/FlatList) hooks that return renderable overlays, replacing
manual WebDesktopScrollbarOverlay wiring across all consumers. Apply the
themed scrollbar to the message input textarea. Tint the dark-mode scrollbar
handle to match the teal-tinted dark theme.
Closes#174
Set native window backgroundColor to match the app's surface0 color so
the backing layer is dark during resize repaints. Extend the existing
updateWindowControls IPC to also call setBackgroundColor on all platforms
(including macOS), keeping the renderer as the single source of truth
for theme resolution. Add a prefers-color-scheme CSS rule in index.html
to cover the HTML-to-React mount gap.
Add Tab, F1-F12, Delete, Home, End, PageUp, PageDown, Insert to the
key map so they can be captured during rebinding. Show held modifier
keys (Ctrl, Alt, Shift, Cmd) as live feedback matching VS Code's
keydown-only approach — modifiers persist after release until the
next keypress. Cancel capture when navigating away from settings.
Windows daemon paths like C:\Users\... don't start with "/", breaking
the explorer sidebar, checkout status, terminals, and file attachments
when connected to a Windows daemon. Consolidate three private
isAbsolutePath implementations into a shared utility and use it
everywhere, with correct file URI conversion for Windows and UNC paths.
Replace the stateful TitlebarDragRegion (hooks, ResizeObserver, IPC,
fullscreen tracking) with a pure static component — matching VS Code's
titlebar-drag-region exactly: position absolute, full size, no z-index,
no pointer-events, no state, no event listeners.
Remove TitlebarNoDragContent entirely — VS Code doesn't wrap content in
no-drag; interactive elements get no-drag from the global CSS backstop
in index.html.
Add drag regions to all header surfaces:
- ScreenHeader (sessions, workspace header)
- Left sidebar (traffic light area + header)
- Split container pane tabs
- Explorer sidebar header (Changes/Files tabs)
Fix workspace header empty space not draggable by changing
headerTitleContainer from flex: 1 to flexShrink: 1.
- Make PaseoLogo theme-aware (uses foreground color instead of hardcoded white)
- Add shadow tokens (sm/md/lg) to theme with per-scheme opacity, radius, and offset
- Replace all 16 hardcoded shadow instances with spreadable theme.shadow tokens
- Fix button icon color for default variant (use accentForeground, not foreground)
- Fix dark background flash on startup (root layout used hardcoded darkTheme)
- Add theme.colorScheme to replace fragile hex-string dark mode detection
- Add scrollbarHandle and surfaceWorkspace tokens to eliminate isDark branching