Use Zustand persist middleware with localStorage to remember onboarding
completion across app restarts. Only the completed flag is persisted;
transient UI state resets each launch. Add --force-onboarding CLI flag
to re-show onboarding even when already completed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove Combobox component and use a plain text input for model name,
allowing users to enter any model identifier manually.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Save & Test flow: saves API key, then sends a minimal prompt to verify
the provider is reachable. Shows phase-based status (saving/testing/
success/error) with auto-close on success.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace plain text input with Combobox for model selection. Users can
search and select from the provider's model list via dropdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace bg-muted/30 with border-l for a clean separator between the
prompt list and ChatView panels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed check from availableProviders.length > 0 to current?.available,
so Continue is only enabled when a provider is both configured and
selected as the active default.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace simple prompts with ones that demonstrate real agent
capabilities: web search, project analysis, and shell execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Continue button is now disabled until the bot status is 'running'.
Skip remains available when no token has been entered.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fake sample prompts with real agent interaction. Clicking a
prompt sends it via localChat and shows the live ChatView on the right
panel with streaming responses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OpenRouter requires both API key and model name. Adds optional model
input field to ApiKeyDialog, enabled via showModelInput prop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents pre-selecting an unconfigured provider and enabling Continue
when no provider is configured. Also passes modelId through on success.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add complete onboarding wizard: Permissions > Provider > Connect > Try it
Step 1 (Permissions): Privacy & Trust acknowledgements with toggles for
file system, shell execution, LLM requests, and local storage access.
Step 2 (Provider): LLM provider setup with 4 supported providers
(Kimi Code, Claude Code OAuth, Codex OAuth, OpenRouter), default
provider selection via radio indicator, and contextual setup tutorials
in the right panel that change on hover.
Step 3 (Connect): Optional Telegram bot connection with token input and
BotFather tutorial. Reuses existing useChannels() hook.
Step 4 (Try it): Sample prompts and completion.
Includes OnboardingGuard, Zustand store (no persist - resets on launch),
breadcrumb stepper with progress bar, and left-right split layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add titleBarStyle hiddenInset and trafficLightPosition to BrowserWindow.
Add drag region to main layout header with no-drag on interactive elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move renderer files to src/renderer/src/ (electron-vite standard)
- Move index.html to src/renderer/
- Remove root: '.' config that broke HMR
- Use ELECTRON_RENDERER_URL instead of VITE_DEV_SERVER_URL
- Update tsconfig paths for new structure
This fixes hot module replacement not working after the monorepo
restructure. The previous non-standard directory layout with root: '.'
caused electron-vite's HMR to fail silently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add clientName field to DeviceMeta so non-browser clients (Telegram,
Discord, etc.) can provide a human-readable label instead of relying on
userAgent parsing. Desktop UI now prioritizes clientName over parsed UA
string, fixing "Unknown on Unknown" display for Telegram connections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The provider & model dropdown now scrolls internally instead of
causing the whole page to scroll when content exceeds viewport.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add model selector section below the provider grid in the dropdown.
Shows available models for the current provider with active model
indicator. Clicking a model calls setProvider with the modelId.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
grammy was not in rollupOptions.external, causing the channels IPC
handlers to fail at runtime with 'No handler registered'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Style is now solely managed by the agent editing soul.md directly,
removing the need for UI controls, IPC handlers, and typed constants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the agent fails due to missing API key, the error banner now
shows a "Configure" button that opens the same ApiKeyDialog (or
OAuthDialog) used on the home page. After successful configuration
the error clears and the user can immediately start chatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix double useChannels() instantiation: call once in ChannelsPage,
pass as props to TelegramCard
- Mask bot tokens in channels:getConfig before sending to renderer
- Add input validation (isValidId, token length) on all IPC handlers
- Fix stopAccount() to clean up typingTimer, lastRoute, aggregator,
and debouncer when stopping the account they belong to
- Add try/catch to stopChannel/startChannel in useChannels hook
- Consistent return type { ok, error? } on channels:stop handler
- Add tooltip hint on disabled Remove button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add IPC handlers, preload API, useChannels hook, and Channels page UI.
Users can save/remove Telegram bot tokens and start/stop bots directly
from the desktop app with immediate effect and persistence across restarts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use setWindowOpenHandler to intercept window.open calls and route
them through shell.openExternal instead of navigating inside Electron.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the agent encounters an error (e.g. no API key configured),
the Chat UI now shows an error banner instead of silently hanging.
The user can still type and retry after fixing their configuration.
- Add AgentErrorEvent to SDK stream types
- Forward agent_error events through IPC to renderer
- Handle error events in useLocalChat hook
- Keep chat input enabled for AGENT_ERROR (retriable)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Forward agent_error as passthrough event to renderer. Add
clearLastRoute() calls in hub:sendMessage and localChat:send
handlers so channel replies stop when desktop sends a message.
Handle agent_error in use-local-chat to show error UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Announcement messages from subagent completion flows were persisted as
regular user messages, polluting conversation history and leaking
orchestration instructions to frontend/CLI.
- Add `internal?: boolean` to SessionEntry message variant
- SessionManager.saveMessage accepts { internal: true } option
- SessionManager.loadMessages filters internal by default
- Agent.runInternal() tags messages as internal, rolls back from memory
- Agent.withRunMutex() prevents concurrent run/runInternal mis-tagging
- AsyncAgent.writeInternal() suppresses event forwarding during internal runs
- Announce flows use writeInternal() instead of write()
- Desktop IPC getHistory reads from session storage (filtered)
- CLI session show parses SessionEntry, supports --show-internal flag
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Cron" tab to navigation bar with Time04Icon
- Add /crons route with CronsPage component
- Add cron IPC handlers (list, toggle, remove) in electron/ipc/cron.ts
- Expose cron API in preload.ts for renderer process
- Add useCronJobs hook for fetching and managing jobs
- Add CronJobList component with status badges, toggle switches,
delete buttons, relative time display, and empty state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'group:cron' to TOOL_GROUPS in IPC handler and agent tools
- Add cron tool description and group name to use-tools hook
- Add Time04Icon for cron group in tool-list component
- Add subagent group icon (UserMultipleIcon) for completeness
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Return latest messages by default instead of oldest. Support paginated
loading of older messages when scrolling up via IntersectionObserver,
with scrollHeight compensation to preserve scroll position.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use chatRef to hold stable reference to useChat return value, avoiding
stale closure issues and satisfying react-hooks/exhaustive-deps rule.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add LocalChat component using useLocalChat hook that communicates with
the Hub via IPC (no Gateway required). Fix streamId extraction to use
event.message.id matching Hub behavior. Fix history to return raw
AgentMessageItem[] instead of flattened strings. Add exec approval
forwarding over IPC. Use conditional rendering for LocalChat to prevent
event leaking from remote sessions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove "requires API key" wording and rebrand to Devv Search across
tool definition, desktop UI, system prompt, and README.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>