Commit Graph

1992 Commits

Author SHA1 Message Date
Mohamed Boudra
727aa0cdac chore(release): cut 0.1.58 2026-04-16 19:17:37 +07:00
Mohamed Boudra
a11c246bdc fix(server): share send-prompt path between MCP and Session
Extract `unarchiveAgentState` and `sendPromptToAgent` into `mcp-shared`
so every surface (app/WS, MCP, CLI-through-MCP) runs the same sequence:
unarchive → ensureAgentLoaded → optional mode change → recordUserMessage
→ startAgentRun. MCP `send_agent_prompt` previously skipped unarchive and
cold-agent rehydration, so sending to an archived agent over MCP left it
hidden from `paseo ls` and failed entirely when the agent wasn't already
in memory. Session now delegates to the shared function and its private
`unarchiveAgentState` is gone.
2026-04-16 18:58:31 +07:00
Mohamed Boudra
2e95003154 fix(server): include stderr in claude auth status diagnostic
Some status output (e.g. "Not logged in") goes to stderr. Capture both
stdout and stderr, including when the command exits non-zero, so the
diagnostic surfaces the full picture.
2026-04-16 18:54:56 +07:00
Mohamed Boudra
1b4483615a fix(server): surface raw claude auth status in diagnostic
Return stdout verbatim instead of parsing JSON fields. Parser was fragile
to upstream schema changes and added no value — users can read the raw
output directly.
2026-04-16 18:52:28 +07:00
Mohamed Boudra
4d0fe57a7a fix(server): stop detecting Windows PowerShell shims 2026-04-16 18:36:06 +07:00
Mohamed Boudra
14ac6984f3 fix(server): extend refresh_providers_snapshot timeout to 60s
Provider snapshot refresh was timing out at 5s for providers that need
longer to enumerate models/auth. Bump to 60s.
2026-04-16 18:29:40 +07:00
Mohamed Boudra
b6147e39ab feat(server): show Claude auth status in provider diagnostic
Runs `claude auth status` and surfaces the parsed result (auth method,
subscription, email/org) in the Claude Code provider diagnostic panel.
2026-04-16 18:29:38 +07:00
Mohamed Boudra
a2b743a6d3 fix(server): emit valid MCP list_agents payloads
Explicit `undefined` keys on optional snapshot fields were converted
to `null` by `ensureValidJson`, failing `AgentSnapshotPayloadSchema`
validation on the wire. Stop writing those keys so they remain absent,
which is what `.optional()` expects.

Also adds a test that parses `list_agents` output through the schema
to catch this class of bug.
2026-04-16 18:29:34 +07:00
Mohamed Boudra
7442323ca2 fix(server): preserve JSON args for Windows PowerShell shims 2026-04-16 18:04:17 +07:00
Mohamed Boudra
086b3098b1 fix(server): support Windows PowerShell shims in shared launcher 2026-04-16 17:58:12 +07:00
Mohamed Boudra
e0f82e7ad0 test(server): reproduce Windows ps1 shim launch gap 2026-04-16 17:52:44 +07:00
Mohamed Boudra
9cee1d8196 fix(server): restore .cmd shell routing for Windows EINVAL 2026-04-16 17:05:08 +07:00
Mohamed Boudra
c2a8e56d33 test(server): reproduce Windows EINVAL for .cmd shim with shell:false 2026-04-16 17:00:01 +07:00
Mohamed Boudra
de33dfd034 fix(server): share Windows launch handling across providers 2026-04-16 16:44:24 +07:00
Mohamed Boudra
917c2f56f4 test(server): reproduce Windows spawn EINVAL with cmd shim + spaces + JSON args 2026-04-16 16:37:17 +07:00
Mohamed Boudra
41fd45588f chore(release): cut 0.1.57 2026-04-16 16:16:30 +07:00
Mohamed Boudra
7c50b7a080 fix(server): harden Codex/Windows startup and provider resolution (#454)
* fix(server): harden Codex/Windows startup and provider resolution

Addresses #452, #443, #353, #418, #403, #221, #307, and locks in #284.

- Replace custom where.exe/which output parsing with npm `which@^5` plus a
  spawn probe. findExecutable now enumerates all PATH+PATHEXT candidates
  and returns the first invokable one. A WindowsApps-ACL'd codex.exe no
  longer wins over a working codex.cmd (#452).
- Make default provider isAvailable() check the binary instead of always
  returning true. Codex/Claude/OpenCode default isAvailable() now defer
  to isCommandAvailable() so missing CLIs surface as unavailable instead
  of throwing later from spawn (#221, #443).
- Gate AgentManager.resumeAgentFromPersistence on isAvailable() so a
  persisted agent record with a missing binary cannot reach provider
  spawn during rehydration. The daemon stays up and the agent reports
  unavailable (#443, #353, #418, #403).
- Drop --path-format=absolute from rev-parse callers and validate stdout
  through a shared parser that rejects multi-line output and unknown-flag
  echoes. --show-toplevel is absolute by default in modern Git;
  --git-common-dir is resolved against the command cwd. Fixes workspace
  registration on pre-2.31 Git that echoed the unknown flag and produced
  a two-line "path" (#307).

Tests:
- Real-FS executable.test.ts using temp PATH fixtures, covering the .cmd
  fallback after .exe pre-spawn failure (Windows-only) plus the
  null-on-no-invokable-candidate case.
- provider-availability.test.ts builds real provider clients against a
  temp-dir-only PATH for Codex/Claude/OpenCode.
- bootstrap-provider-availability.test.ts builds the daemon and triggers
  ensureAgentLoaded so it actually exercises resumeAgentFromPersistence.
- claude-agent.spawn.test.ts asserts shell: false reaches spawnProcess
  from the Claude SDK spawn override, locking in 39b56af4 for #284.
- checkout-git-rev-parse.test.ts covers nested-checkout resolution and
  the old-Git multi-line stdout case via a tightly-scoped runGitCommand
  fake.

CI:
- server-tests-windows now also runs the new and modified test files so
  the Windows behaviors are exercised on windows-latest.

* fix: update lockfile signatures and Nix hash

* fix(server): handle synchronous spawn UNKNOWN on Windows

On Windows, child_process.spawn() throws synchronously when invoked on
a corrupt or invalid .exe (e.g., a WindowsApps stub the current user
cannot execute, or a zero-byte file). The executable probe did not
guard the spawn call, so the synchronous throw rejected the probe
promise instead of resolving false, preventing findExecutable() from
trying the next candidate. This is the root cause of the daemon-crash
pattern in #452: codex.exe from WindowsApps would hard-fail before the
.cmd shim ever got a chance.

Wrap spawn() in try/catch and settle false on sync throw. The existing
error-event and exit-event handlers already cover async failure modes;
sync throw just needed one more guard.

Also adjust three Windows-only test comparisons that were asserting
platform-dependent string equality:
- executable.test: compare .cmd paths case-insensitively (which@5
  preserves PATHEXT casing, which is uppercase in production).
- workspace-registry-model.test: expect normalizeWorkspaceId(path),
  not the hardcoded POSIX form.
- checkout-git-rev-parse.test: normalize separators/case when
  comparing git's Windows forward-slash output against realpathSync.

* test(server): canonicalize repo root via git on Windows to fix short-name mismatch

realpathSync on Windows preserves 8.3 short names (e.g. RUNNER~1) while git's
rev-parse --show-toplevel always returns the long-name form (runneradmin).
Use git as the canonicalizer on both sides of the assertion so the comparison
holds regardless of how Windows exposes the temp directory path.

* fix(server): Claude is always available in default mode; SDK bundles cli.js

The Phase 2 change wrongly tied Claude's default-mode isAvailable() to
isCommandAvailable("claude"). Claude's default runtime does not use an
external `claude` binary — @anthropic-ai/claude-agent-sdk ships its own
cli.js and spawnClaudeCodeProcess runs it via process.execPath. The
previous `return true` was correct; restore it.

Update provider-availability.test.ts to assert the truthful behavior:
Claude reports available even when no `claude` binary is on PATH.

Codex and OpenCode genuinely require their binaries on PATH, so their
availability checks remain unchanged.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-16 16:36:13 +08:00
Mohamed Boudra
11b407c804 fix(app): hide branch icon on non-git workspace headers
Gate the GitBranch icon behind isGitCheckout, and keep the header
skeleton visible until the checkout status query resolves so the icon
doesn't pop in and cause layout shift.
2026-04-16 13:14:00 +07:00
Mohamed Boudra
814098852c feat: provider model freshness TTL and diagnostic UI (#426)
* feat: add server-side TTL for provider snapshots and model list UI

Provider snapshots cached forever, causing newly available models
(e.g. OpenCode Go minimax, glm) to never appear in the picker.

Server: ProviderSnapshotManager now returns stale data immediately
and kicks off a background re-warm when the snapshot is older than
5 minutes. Injectable TTL/clock for testing.

App: Provider settings rows show model count and are tappable to
open a diagnostic sheet with a read-only model list (label + ID).

* feat: add per-provider refresh for models and diagnostic

* refactor: await refresh completion and clean up diagnostic sheet state

- ProviderSnapshotManager.refresh is now async; session.ts awaits it so
  the RPC ACK reflects real completion instead of just queuing work.
- Preserve models/modes/fetchedAt on entries during targeted refresh so
  the list no longer flashes empty mid-refresh.
- Show "Updated Xs ago" next to the Models count, plus loading and
  error states for the list body.
- Split resetSnapshotToLoading into full vs targeted branches.
- Flatten nested ternary in model list rendering into renderModelsBody.
- Drop redundant local refreshing state and cargo useMemo wrappers.

* fix(app): widen isImeComposingKeyboardEvent type to accept optional fields

TextInputKeyPressEventData has isComposing and keyCode as optional, so
Pick<KeyboardEvent, ...> was too narrow and broke typecheck on main.
2026-04-16 13:14:02 +08:00
Li Mu Zhi
5c6f175db5 fix: make code file preview text selectable on iOS (#447)
Add `selectable` prop to the code line Text component so users can
long-press to select and copy text on iOS. On web/desktop this is
already the default behavior via CSS user-select.

Markdown file preview has a similar issue but requires a different
fix (custom rules for react-native-markdown-display), left for a
follow-up.

Refs #238
Related #21

Co-authored-by: muzhi1991 <muzhi1991@limuzhideMac-mini-2.local>
2026-04-16 11:06:16 +08:00
Aaron Florey
165ae58f75 fix(server): Improve OpenCode permission prompt context (#398)
Surface structured permission detail for OpenCode requests so clients can show command intent and richer context instead of generic placeholders. Humanize permission titles and include scope/reason metadata to make approval decisions clearer.
2026-04-16 11:01:56 +08:00
amir
a1f3256923 style(app): theme native scrollbars across all web views (#399)
* style(app): theme native scrollbars in tool call detail views

Apply CSS scrollbar-color to all ScrollViews in ToolCallDetailsContent
and DiffViewer so the browser scrollbar matches the app's dark theme
instead of showing the default white native scrollbar.

* refactor: split useWebScrollbarStyle into .web.ts/.native.ts platform files

- Native shim returns undefined without calling useUnistyles
- Web variant uses properly typed WebScrollbarStyle interface instead of `as any`
- Add .d.ts for TypeScript module resolution

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-04-16 10:59:31 +08:00
Mohamed Boudra
86bb5cc827 fix: make MCP tools work for archived agents, matching CLI code paths (#423)
Extract shared functions from session.ts (toAgentPersistenceHandle,
buildStoredAgentPayload, ensureAgentLoaded) so both CLI/WebSocket
handlers and MCP tools use the same code paths for agent lookup.

Fix get_agent_status, get_agent_activity, and list_agents MCP tools
to fall back to persistent storage for archived agents. Add
includeArchived param to list_agents. Fix setupFinishNotification
to not wake archived callers. Delete dead agent-management-mcp.ts.
2026-04-16 10:44:57 +08:00
Mohamed Boudra
483312e1dc feat: add disallowedTools to provider config
Allow providers to specify tools that should be disabled via a
disallowedTools array in config.json. This is useful for providers
that extend "claude" but point to third-party API endpoints that
don't support Anthropic-only server-side tools like WebSearch.

Closes #390
2026-04-16 09:42:54 +07:00
Edvard Chen
0b3c29b2ec fix(desktop): allow localhost origins in dev (#419)
Desktop dev uses Electron pages on random localhost ports, so the daemon must accept those websocket origins during local development.
2026-04-16 10:34:30 +08:00
Aaron Florey
1885d8602f feat(app): Render markdown files in file pane (#427)
Detect .md and .markdown files in the shared file pane and render them as markdown instead of syntax highlighted code. This makes README-style files easier to read without changing the existing preview flow for other text files or .mdx.

Keep the change focused to the app renderer by reusing the existing markdown stack and adding a narrow extension check with targeted coverage.
2026-04-16 10:33:49 +08:00
Aaron Florey
57312d4f75 fix(server): Map OpenCode todo and compaction events (#429)
Translate OpenCode todo and compaction events into Paseo timeline items so issue #106 uses the existing todo list and compaction UI without changing the client model.

Keep session.status handling limited to existing terminal states and add focused translator coverage for each mapped event.

Fixes #106

Co-authored-by: OpenCode <noreply@openai.com>
2026-04-16 10:29:05 +08:00
Rui Fan
ffbb2ffd06 fix: retry file explorer init when client reconnects after page refresh (#442)
hasInitializedRef was set to true before confirming the directory
listing request actually succeeded. On page refresh the WebSocket
client is still reconnecting, so requestDirectoryListing returned
early with "Host is not connected" and the ref stayed true —
preventing any retry once the client became available.

Fix: make requestDirectoryListing return Promise<boolean> and reset
hasInitializedRef on failure so the init effect re-runs automatically
when requestDirectoryListing is recreated after the client reconnects.

Fixes #441

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 10:28:02 +08:00
Edvard Chen
45a5ba8637 Fix duplicate command args for generic ACP providers (#444)
* Fix duplicate command args for generic ACP providers

* Fix desktop IME enter handling
2026-04-16 10:23:05 +08:00
Mohamed Boudra
deca82653e chore(release): cut 0.1.57-rc.1 2026-04-15 21:02:07 +07:00
Mohamed Boudra
4e9d80d118 fix: prevent model name truncation in combobox item rows 2026-04-15 19:25:24 +07:00
Li Mu Zhi
918949c7fa fix: file preview shows stale content when re-opening a file (#411)
* fix: file preview shows stale content when re-opening a file

The file content query inherits `refetchOnMount: false` and
`gcTime: Infinity` from the global QueryClient defaults, so
re-opening a previously viewed file never re-fetches its content.

Set `staleTime: 0` and `refetchOnMount: true` on the file preview
query so it always fetches the latest content when the component
mounts.

Fixes #351

* fix: keep original staleTime, only add refetchOnMount

staleTime: 5_000 is reasonable — avoids redundant fetches when
quickly toggling the same file. The actual fix only needs
refetchOnMount: true to override the global default of false.

---------

Co-authored-by: muzhi1991 <muzhi1991@limuzhideMac-mini-2.local>
2026-04-15 13:24:14 +08:00
Mohamed Boudra
7a8f65805d refactor: rename allowedHosts to hostnames (#413)
* refactor: rename allowedHosts to hostnames for DNS rebinding config

The old name confused users who thought it was related to CORS.
"hostnames" communicates that you're declaring the daemon's own
hostnames, not granting access to external parties.

Backward compatible: old config files (daemon.allowedHosts), env var
(PASEO_ALLOWED_HOSTS), CLI flag (--allowed-hosts), and Nix option
(allowedHosts) all still work as deprecated aliases.

* fix(nix): update npmDepsHash to match current package-lock.json
2026-04-15 12:47:49 +08:00
Mohamed Boudra
fc96b260d1 refactor: rename isInputActive to isPaneFocused for clarity
The prop represents whether the pane/panel is focused, not whether the
text input is focused. Rename across all 5 files to match the caller
names and reduce confusion.
2026-04-15 10:36:36 +07:00
Mohamed Boudra
3fe79535cc fix: only show ⌘L focus hint when agent panel is active 2026-04-15 10:33:42 +07:00
Mohamed Boudra
d40e4b6f0d feat: add ⌘L shortcut to focus message input with hint
Show a muted "⌘L to focus" hint in the top-right of the message input
when unfocused and empty on web. Registers Cmd+L (Mac) / Ctrl+L
(non-Mac) bindings for the existing message-input.focus action.
2026-04-15 09:57:05 +07:00
Aaron Florey
8f04e65cf1 fix(opencode): Wait for SSE after slash command timeouts (#407)
Treat OpenCode slash-command header timeouts as recoverable transport failures so Paseo waits for the SSE terminal event instead of failing the turn immediately.

Add a regression test for the timeout path to keep slash commands aligned with the existing event-stream completion flow.
2026-04-15 10:52:58 +08:00
Aaron Florey
c5295a4ab3 fix(server): archive OpenCode sessions on close (#408)
Reconcile OpenCode provider state when Paseo closes or archives an agent so upstream sessions do not remain active after local teardown.

Keep the close path idempotent by attempting an abort first and then marking the upstream session archived even when the run is already idle or missing.

Fixes #400

Co-authored-by: OpenCode <noreply@openai.com>
2026-04-15 10:52:15 +08:00
Mohamed Boudra
f59af4c810 fix: catch unhandled timeout rejection in attention clear
clearAgentAttention returns a promise that was never caught,
causing uncaught rejection errors on daemon timeout.
2026-04-15 09:16:09 +07:00
Mohamed Boudra
e012c8f52e feat: return agent snapshots from cancel and clear-attention RPCs
Convert cancel_agent_request and clear_agent_attention from
fire-and-forget to request/response RPCs that return the authoritative
agent snapshot. This enables client-side self-healing when agent_update
messages are missed (e.g. agent appears stuck running when it isn't).
2026-04-14 23:21:37 +07:00
Mohamed Boudra
312a6e22fe fix: flush head before applying canonical catch-up entries on mobile
On mobile, the server drops live stream events for backgrounded or
unfocused agents.  When the user returns, a seq gap triggers a
catch-up fetch whose canonical entries are appended to the tail —
but the head was never flushed.  Stale live items from before the
gap stayed in the head and rendered after the newer catch-up entries,
breaking chronological order.  Worse, subsequent live events of the
same kind (e.g. assistant_message) would append to the stale head
item, garbling message content.

Now the incremental path in processTimelineResponse flushes head →
tail before reducing canonical entries, keeping the timeline ordered
and the head clean for new live events.
2026-04-14 23:03:23 +07:00
Mohamed Boudra
7f92f7f51d fix: stabilize branch switcher layout on mobile
Always render the GitBranch icon regardless of branch availability so
the layout doesn't shift when the branch name loads. Only the chevron
remains dynamic. Also removes vertical padding on mobile to tighten
the gap between the branch row and project subtitle.
2026-04-14 22:27:06 +07:00
Mohamed Boudra
d4a4015804 chore(release): cut 0.1.56 2026-04-14 21:15:53 +07:00
Mohamed Boudra
c8cafbabff chore(release): cut 0.1.56-rc.1 2026-04-14 20:56:11 +07:00
Mohamed Boudra
f0ac632732 fix: isolate git snapshot errors per workspace in fetch_workspaces
A single workspace failing to load git data (e.g. empty repo, corrupt
git state) was crashing the entire fetch_workspaces response, leaving
all users with an unusable app. Now errors are caught per-workspace
and logged as warnings, returning the workspace without git data.
2026-04-14 20:54:11 +07:00
Mohamed Boudra
25fd93d7e2 fix: handle repos with no commits in getCurrentBranch
git rev-parse --abbrev-ref HEAD fails with exit code 128 on freshly
initialized repos with no commits. This error bubbled up through
workspace listing and showed a toast error on every app launch for
users with empty git repos.
2026-04-14 20:49:54 +07:00
Mohamed Boudra
c70277f445 chore(release): cut 0.1.55 2026-04-14 20:15:14 +07:00
Mohamed Boudra
8651c334c7 fix: keep worktree creation spinner visible while loading
The new-worktree button spinner was hidden when the cursor left the
project row. Force visibility when the mutation is pending so users
see the loading state throughout creation.
2026-04-14 19:43:08 +07:00
Mohamed Boudra
d1702e8a40 fix: defer worktree git watch subscription until after worktree exists
registerPendingWorktreeWorkspace was subscribing the WorkspaceGitService
before the worktree directory existed on disk, caching a stale isGit:false
snapshot. When background reconciliation ran, it consumed the stale cache,
overwrote the correct workspace record with a wrong projectId, and briefly
showed the worktree as a standalone project in the sidebar.

Move syncWorkspaceGitWatchTarget from registerPendingWorktreeWorkspace into
handleCreatePaseoWorktreeRequest, called after createAgentWorktree, so the
first snapshot sees the real worktree — one subscribe, one load, no stale
cache to race against.
2026-04-14 19:38:47 +07:00
Mohamed Boudra
80eb5dbe83 fix: make workspace-git-service tests platform-aware for Linux CI
The requestWorkingTreeWatch tests assumed macOS/Windows behavior where
recursive fs.watch is attempted. On Linux, the service uses per-directory
watchers instead, so recursive is never tried.
2026-04-14 19:20:59 +07:00