- Deleted the .eslintrc.cjs file to simplify configuration management.
- Updated lint scripts in package.json to remove unnecessary extensions for linting.
- Added new devDependencies for ESLint and globals to enhance linting capabilities.
- Move ChatToolbar (session selector, refresh, thinking toggle) from
the Chat page body into the Header component, so controls appear
at the same level as the "Chat" title
- Add New Session button (+) to create a fresh conversation
- Add newSession action to chat store
- Header conditionally renders ChatToolbar only on /chat route
- Chat page fills full content area without duplicate toolbar
Replace the iframe-based Control UI embed with a native React
implementation that communicates directly with the Gateway via
gateway:rpc IPC calls and chat event streaming.
New components:
- ChatToolbar: session selector dropdown, refresh button, thinking toggle
- ChatMessage: message bubbles with markdown (react-markdown + GFM),
collapsible thinking blocks, tool use cards, image attachments
- ChatInput: textarea with Enter to send, Shift+Enter for new line
- message-utils: extractText/extractThinking/extractImages/extractToolUse
ported from OpenClaw's message-extract.ts
Rewritten chat store with:
- Session management (sessions.list, switchSession)
- Proper chat.history loading with raw message preservation
- chat.send with idempotencyKey and run tracking
- Streaming via handleChatEvent (delta/final/error/aborted)
- Thinking toggle (show/hide reasoning blocks)
The Dashboard crashed with 'channels.slice is not a function' because
channels.status returns a deeply nested object per channel ID, not a
Channel[] array. Same issue with skills.status.
For now, use empty arrays since channel/skill management is deferred
to their dedicated pages. Will properly parse the complex response
format when those pages are implemented.
- The session.webRequest.onHeadersReceived was stripping X-Frame-Options
and modifying CSP for ALL responses including the Vite dev server,
which could break the main app rendering. Now only applies to
gateway URLs (127.0.0.1:18789 / localhost:18789).
- Dashboard: only fetch channels/skills when gateway is running
- Dashboard: guard against non-array channels/skills data
- Gateway store: use dynamic import() instead of require() for chat
store to avoid ESM/CJS issues in Vite
- Fix channels store: use channels.status instead of channels.list
- Fix skills store: use skills.status instead of skills.list
- Fix chat store: correct chat.history response parsing (messages in payload)
- Fix chat store: handle chat.send async flow (ack + event streaming)
- Add chat event handling for streaming AI responses (delta/final/error)
- Wire gateway:chat-message IPC events to chat store
- Fix health check: use WebSocket status instead of nonexistent /health endpoint
- Fix waitForReady: probe via WebSocket instead of HTTP
- Gracefully degrade when methods are unsupported (no white screen)
- Replace mock API key validation with actual API calls to verify keys
- Add validateApiKeyWithProvider() with provider-specific implementations
- Support Anthropic, OpenAI, Google, and OpenRouter validation
- Add OpenRouter as a new provider option in setup wizard and settings
- Fix setup page to call real validation instead of mock length check
- Allow validation during setup before provider is saved
- Return user-friendly error messages instead of raw API errors
- Add AppUpdater module with update lifecycle management
- Create UpdateSettings UI component with progress display
- Add Progress UI component based on Radix UI
- Create update Zustand store for state management
- Register update IPC handlers in main process
- Auto-check for updates on production startup
- Add commit documentation for commits 2-6