Commit Graph
93 Commits
Author SHA1 Message Date
Mohamed Boudra 925752c8a3 Update files 2026-02-08 17:50:43 +07:00
Mohamed Boudra 4a9cf9e90f Update files 2026-02-07 09:43:44 +07:00
Mohamed BoudraandGitHub d724988542 Fix agent history catch-up + avoid mobile background stream deltas (#18)
* Update files

* Fix agent history sync + mobile stream gating
2026-02-06 13:18:15 +07:00
Mohamed Boudra ae27a14e3b Update files 2026-02-05 12:02:25 +07:00
Mohamed Boudra 0218729316 Relay pairing offer v2 (E2EE) + host connections 2026-02-04 22:53:00 +07:00
Mohamed Boudra 1039171167 Merge origin/main into daemon-server-id-host-selection 2026-02-04 15:19:06 +07:00
Mohamed Boudra 6aff4b3f10 Merge branch 'plan/e2ee' - End-to-end encryption for relay connections
Implements E2EE for relay connections only, keeping direct connections
and CLI plaintext. The relay acts as a dumb byte forwarder with no
access to decrypted messages.

Key changes:
- Daemon keypair persistence in $PASEO_HOME/daemon-keypair.json
- Encrypted relay transport using ECDH P-256 + AES-256-GCM
- Client-side E2EE using daemon's public key from pairing offer
- WebCrypto compatibility for React Native
2026-02-04 15:00:34 +07:00
Mohamed Boudra 8152deb206 Update files 2026-02-04 14:58:18 +07:00
Mohamed Boudra 9e9b8c3108 Merge branch 'main' into keyword-nav-plan
# Conflicts:
#	packages/app/src/components/agent-input-area.tsx
#	packages/app/src/components/command-center.tsx
#	packages/app/src/hooks/use-global-keyboard-nav.ts
2026-02-04 13:01:17 +07:00
Mohamed Boudra 94b12ba8e3 Update files 2026-02-04 10:35:08 +07:00
Mohamed Boudra 79aec0069c Improve daemon RPC resiliency and diff handling 2026-02-04 10:21:36 +07:00
Mohamed BoudraandGitHub 469a25c724 feat: add live model and thinking option preferences UI (#8)
* feat: add live model and thinking option preferences UI

* refactor: remove agent variant support and clean up thinking options

* feat: live model + thinking presets (RPC)
2026-02-04 08:18:15 +07:00
Mohamed Boudra 6ed70e24c7 feat: implement end-to-end encryption for relay connections 2026-02-03 13:40:44 +07:00
Mohamed Boudra af89de1237 feat: add presence-gated Expo push notifications 2026-02-03 12:59:00 +07:00
Mohamed Boudra bf9555829b refactor: replace agent_list polling with request/response RPC pattern 2026-02-01 22:37:32 +07:00
Mohamed Boudra 0618dc6b0d refactor: rename session_state to agent_list and add subscriptions 2026-01-30 13:39:40 +07:00
Mohamed Boudra c015fdbef1 refactor: replace agent-control MCP with labels system and Paseo MCP 2026-01-29 11:31:15 +07:00
Mohamed Boudra f7935f9cc1 Update files 2026-01-28 15:25:12 +07:00
Mohamed Boudra 766585d1cb Update files 2026-01-27 13:06:01 +07:00
Mohamed Boudra ae9a98223f refactor: rename conversation to voice conversation throughout stack 2026-01-21 11:43:16 +07:00
Mohamed Boudra d9c487dd54 feat: add Tauri desktop app support and terminal management 2026-01-20 10:09:35 +07:00
Mohamed Boudra ed50c168ad refactor(app): unified panel state machine for mobile sidebars
Replace separate sidebar stores with a unified panel store that uses a
discriminated union state machine on mobile. This makes it impossible
for both the agent list and file explorer sidebars to be open at the
same time on mobile.

Mobile state machine (mobileView):
- 'agent': Main agent view (no overlay panel)
- 'agent-list': Agent list sidebar (left overlay)
- 'file-explorer': File explorer sidebar (right overlay)

Desktop retains independent boolean toggles since sidebars sit
alongside content rather than overlaying it.

Key changes:
- Created stores/panel-store.ts with unified state
- Deleted stores/sidebar-store.ts and explorer-sidebar-store.ts
- Updated all components to use new panel store
- Animation contexts derive isOpen from unified state
2026-01-16 16:19:49 +07:00
Mohamed Boudra 70e2d66dd5 feat: persist draft messages and UI refinements
- Add dedicated draft-store with AsyncStorage persistence for drafts
  that survive app refresh/crash
- Reduce markdown bold weight from bold to medium (500)
- Various theme and component style updates
- Server bootstrap and config improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-14 10:07:54 +07:00
Mohamed Boudra 34a49c147f feat: add smart notification routing with device-aware heartbeats and push support 2026-01-13 16:07:34 +07:00
Mohamed Boudra 868f9fb571 WIP: Large refactor checkpoint
- Refactored daemon client and RPC layer
- Added new client package structure in server
- Removed legacy hooks (use-daemon-request, use-session-rpc, use-websocket)
- Added use-daemon-client hook
- Added e2e test infrastructure with Playwright
- Updated agent providers and session handling
- Removed codex-sdk patches
2026-01-12 13:30:20 +07:00
Mohamed Boudra 32fe3bd4a0 Add OS notifications for agent attention 2026-01-11 23:46:14 +07:00
Mohamed Boudra ebabcc09e5 feat: add opencode provider and refactor stream model to head/tail architecture 2026-01-11 16:00:25 +07:00
Mohamed Boudra 1a2498e9e7 refactor: remove terminal MCP, Playwright, and commands infrastructure
- Remove terminal/tmux MCP from voice LLM - it now only uses agent-control MCP
- Remove Playwright MCP auto-injection from Claude and Codex agents
- Remove commands state from session, store, and UI
- Remove present_artifact tool and guidelines from voice prompt
- Update agent-prompt.md examples to focus on agents instead of commands
- Remove @huggingface/transformers dependency and test scripts
- Add expandTilde utility to utils/path.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-09 13:01:26 +07:00
Mohamed Boudra cc74d6d0d2 feat: remove import agent feature from UI
Remove the import agent functionality from the app while preserving
the underlying resume capability in the agent code.

Changes:
- Remove ImportAgentModal and import flow from create-agent-modal.tsx
- Remove "Import Agent" menu item from agent screen
- Remove "Import" button from home footer
- Remove resumeAgent from session context and store
- Remove list_persisted_agents WS messages from server
- Remove handleListPersistedAgentsRequest handler
- Clean up unused styles and types

The resumeAgent capability remains in the agent manager for potential
future use or internal tooling.
2026-01-08 21:48:48 +07:00
Mohamed BoudraandClaude Opus 4.5 e8890a2fc1 wip: uncommitted changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 16:06:40 +07:00
Mohamed Boudra 0c4d1c3a58 Buffer streaming chunks to reduce rerenders 2026-01-01 15:43:06 +07:00
Mohamed Boudra 63247f73b3 feat(file-explorer): add file download with share sheet support 2026-01-01 13:07:51 +07:00
Mohamed Boudra 7a024ce7fd Migrate image encoding to expo-file-system File API 2025-12-29 10:51:06 +07:00
Mohamed Boudra 6160d96716 Fix web image base64 encoding 2025-12-29 09:09:53 +07:00
Mohamed Boudra d5f5351d37 Add image attachments to agent creation 2025-12-29 09:07:54 +07:00
Mohamed Boudra 025fd97143 Fix file explorer back loader 2025-12-29 00:10:23 +07:00
Mohamed Boudra 265caaf140 Fix gallery image timeout crash 2025-12-29 00:02:00 +07:00
Mohamed BoudraandClaude Opus 4.5 cb78f29b31 feat: add parentAgentId to client types and session store
Add parentAgentId field to:
- Agent interface in session-store.ts
- AgentDirectoryEntry in agent-directory.ts
- getAgentDirectory() includes parentAgentId
- normalizeAgentSnapshot() maps from server payload

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 17:21:11 +00:00
Mohamed Boudra abe3a42478 feat: add agent runtime info tracking with model detection from rollout files 2025-12-21 23:16:49 +07:00
Mohamed BoudraandClaude 0f1758709d feat: add "Requires Attention" agent grouping feature
Implement a new UI section that surfaces agents requiring user attention at the top of the agent list. This includes agents that are running, have pending permissions, or have errors.

**Backend changes:**
- Add `requiresAttention` field to agent projections and SDK types
- Implement logic in AgentManager to detect attention states (running, pending permissions, errors)
- Add WebSocket message handler to notify clients of attention state changes
- Update session state to include attention tracking

**Frontend changes:**
- Add "REQUIRES ATTENTION" section in agent-list component with visual prominence
- Update useAggregatedAgents hook to expose `requiresAttention` agents
- Enhance session store to track and update attention states
- Add real-time updates via WebSocket for attention state changes
- Update type definitions across agent directory and stream types

Verified working via Playwright MCP testing on localhost:8081.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 11:27:08 +00:00
Mohamed BoudraandClaude 644c654274 perf: prevent HomeScreen rerenders during agent streaming
- Add top-level agentLastActivity Map to store (prevents cascade rerenders)
- Remove lastActivityAt updates from agent_stream handler (only status changes update timestamps)
- useAggregatedAgents now uses agent.lastActivityAt directly
- Remove investigation logging from previous debug session

The root cause was that every stream event updated agent.lastActivityAt,
causing useAggregatedAgents to recalculate, which caused HomeScreen to
rerender even when not visible. Now timestamps only update on meaningful
events (agent status changes), not individual stream tokens.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 17:34:07 +07:00
Mohamed BoudraandClaude 21d43bc249 perf: eliminate cascading rerenders with granular Zustand selectors
- Delete useDaemonSession hook that selected entire session object
- Move drafts to top-level store (not nested in sessions)
- Refactor all components to use granular useSessionStore selectors
- Fix infinite loop bugs from selector fallbacks (use stable constants)

Before: 15-20 component rerenders per keystroke
After: ~1-2 rerenders per keystroke

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 16:37:23 +07:00
Mohamed BoudraandClaude 74c82a312e perf: move drafts to top-level store to prevent session rerenders
Previously, drafts were nested inside each session object, which caused
the entire session to be recreated on every keystroke. This triggered
rerenders in all components subscribed to the session.

Now drafts are stored at the top level of the Zustand store, keyed by
agentId (not serverId:agentId since agent IDs are globally unique).
This means draft updates only trigger rerenders in components that
subscribe to drafts specifically.

Changes:
- Move drafts from SessionState to SessionStoreState (top-level)
- Add createModalDraft for future use by the create agent modal
- Update getDraftInput/saveDraftInput to work with agentId only
- Update session-context to clear drafts using new API
- Remove investigation console.log statements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 15:46:45 +07:00
Mohamed BoudraandClaude e346b4c026 Replace reconnecting badge with pull-to-refresh
UX improvements:
- Remove misleading "Reconnecting..." badge overlay
- Implement native pull-to-refresh gesture on agent list
- Add manual refresh capability via pull gesture

Technical changes:
- Add refreshSession() method to session context
- Add refreshAll() to useAggregatedAgents hook
- Integrate RefreshControl in AgentList component
- Use isRevalidating state for refresh indicator
- Apply theme colors to RefreshControl for consistency

Benefits:
- Familiar iOS/Android UX pattern
- No UI overlays blocking content
- Clear user action (pull) → clear feedback (refresh)
- Accurate state representation (syncing vs reconnecting)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 02:57:38 +00:00
Mohamed BoudraandClaude 348cb9d637 Fix loading state bugs and server crash
Backend fixes:
- Fix server crash when logging large session_state messages (186 agents)
- Use safe logging that extracts only message/stack properties
- Prevents TypeError in util.inspect on circular refs or deep objects

Frontend loading state fixes:
- Add reactive WebSocket update to prevent stale session.ws references
- Add timeout/retry wrapper for session_state loading (3 retries × 15s)
- Add hasEverReceivedSessionState flag to track cached data across reconnects
- Implement data-aware loading (isInitialLoad vs isRevalidating)
- Show reconnecting badge instead of hiding agents on reconnect

Debug improvements:
- Add detailed connection state logging in useAggregatedAgents
- Add connection status logging in AgentInputArea
- Track connecting reasons for easier debugging

Fixes:
- Agent screen no longer shows false "Offline" toast on reconnect
- Home screen shows loading immediately (no empty state flash)
- Home screen keeps agents visible during reconnect with badge
- Stuck loading has timeout protection with graceful degradation
- Server no longer crashes when sending session_state with many agents

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 02:45:16 +00:00
Mohamed BoudraandClaude 5ddaea7352 Complete Zustand migration: fix component access to session APIs
Finalizes the pure Zustand refactor by ensuring all components properly access both session state and imperative methods through useDaemonSession. Moves CLAUDE.md to root and ignores local overrides.

Changes:
- Fix useDaemonSession to return stable combined state + methods object
- Update components to use useDaemonSession instead of direct context
- Fix realtime context to work with session state only
- Move CLAUDE.md to root, ignore CLAUDE.local.md for local config
- Add proper null checks and type safety throughout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 17:42:49 +00:00
Mohamed BoudraandClaude f5ec3bffb7 Update agent lastActivityAt on stream events
Problem: lastActivityAt was only updated when agent_state messages arrived
(which only happens on agent lifecycle changes), not when the agent was
actively streaming output. This meant the agent directory showed stale
"last activity" times.

Solution: Update agent.lastActivityAt whenever agent_stream events arrive,
using the event's timestamp. Now lastActivityAt tracks real-time activity.

Updates happen on:
1. agent_state message → lastActivityAt = updatedAt (from server)
2. agent_stream message → lastActivityAt = event.timestamp (real-time!)

This ensures the agent directory always shows fresh activity times.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 14:16:50 +00:00
Mohamed BoudraandClaude 8b87b0a4e2 Remove agent directory syncing, make it pure derived state
Problem: Agent directory was still being synced from SessionProvider to
Zustand store, violating the "SessionProvider is just a message handler"
principle and creating unnecessary state duplication.

Solution: Make agent directory pure derived state:
- Removed agentDirectory from SessionStoreState
- Removed setAgentDirectory/clearAgentDirectory actions
- Changed getAgentDirectory to compute on-demand from session.agents
- Removed buildAgentDirectoryEntries and syncing from SessionProvider
- Updated useAggregatedAgents to derive from sessions directly

How it works now:
- Agent directory is computed on-demand from session.agents Map
- lastActivityAt automatically updates when agents update via WebSocket
- No syncing, no stale state, no overhead
- Single source of truth: session.agents

Benefits:
- Eliminated redundant state (agentDirectory was duplicate of agents)
- No sync overhead or complexity
- Always fresh data (derived on read)
- Simpler mental model (agents is the only source)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 14:15:32 +00:00
Mohamed BoudraandClaude f5c6bce54f Migrate SessionContext to pure Zustand, eliminate hybrid overhead
Problem: SessionContext used useSyncedSessionState which synced every state
update from React useState to Zustand, creating double overhead and complexity.

Solution: Complete migration to pure Zustand architecture:

- session-store.ts is now the single source of truth
  - Moved ALL state directly into Zustand (no React useState)
  - Added per-session state: messages, agents, commands, permissions, etc.
  - Added Zustand actions for all state updates (setMessages, setAgents, etc.)
  - Exported all types (MessageEntry, Agent, Command, etc.)

- session-context.tsx is now a pure WebSocket message handler
  - Removed useSyncedSessionState hook entirely
  - Removed all useState calls for session state
  - Removed sync machinery (syncSessionField, syncSessionPartial)
  - WebSocket handlers now call Zustand setters directly
  - Context only provides imperative APIs (ws, audioPlayer, actions)
  - No state values in context

Architecture change:
  Before: WebSocket → React useState → sync → Zustand (double overhead)
  After:  WebSocket → Zustand directly (single source of truth)

Benefits:
- Eliminated double overhead from React → Zustand syncing
- Single state update per WebSocket message
- Better re-render optimization via Zustand selectors
- Cleaner separation: SessionProvider = message handler, SessionStore = state
- Reduced complexity: removed 400+ lines of hybrid sync code

Backward compatibility:
- useDaemonSession() already reads from Zustand, no changes needed
- Type exports re-exported from session-store for compatibility
- Components work exactly the same

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 14:08:56 +00:00
Mohamed BoudraandClaude 32e111e1bf fix: remove unused focusedAgentId orchestrator logic and timestamp thrashing
This commit implements a critical performance optimization by removing
unused orchestrator logic that was causing thousands of unnecessary
store updates per minute:

1. Removed orchestratorFocusedAgentId state and auto-selection logic
   - The orchestrator auto-selected "most recently active agent"
   - Nothing in the codebase actually reads focusedAgentId
   - Simplified focusedAgentId to just focusedAgentOverride (user selection only)

2. Stopped updating timestamps on every stream event
   - Previously updated lastActivityAt/updatedAt on every agent_stream event
   - These events occur 15+ times per second during streaming
   - Created 2700+ store updates per minute from a single agent

3. Removed focusedAgentId from store sync
   - No longer syncs focusedAgentId changes to the store
   - Reduces cascading updates throughout the app

Expected impact:
- 95%+ reduction in store updates during agent streaming
- Home screen no longer re-renders during agent activity
- Improved UI responsiveness and reduced battery usage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:14:49 +00:00