When continuing an old chat session, CodePilot passes the stored
sdk_session_id to the SDK with resume=true. If the local SDK session
file is stale, corrupt, or incompatible (e.g. after a CLI version
update), the SDK process exits with code 1 and the user sees a
misleading "Invalid or missing API Key" error.
This fix wraps the initial query() call with a try-catch that detects
resume failures by peeking at the first async message. On failure, it
automatically retries without the resume option, starting a fresh SDK
session while preserving the chat history in CodePilot.
- src/lib/claude-client.ts: added resume-failure detection and
automatic fallback logic around the query() call
Streaming tool UI fix (ChatView.tsx):
- Add toolUsesRef/toolResultsRef to reliably track tool data across closures
- Serialize tool_use/tool_result into JSON content-blocks array when building
assistant message after stream ends, matching backend storage format
- MessageItem.parseToolBlocks() now renders tool UI from history messages
- Clean up refs in finally block and timeout auto-retry path
File tree UX (FileTree.tsx, file-tree.tsx):
- Remove folder path header from right panel, merge search + refresh into one row
- Remove file icon spacer (size-5) so file icons align flush with search box
- Change folder icon color from blue to muted-foreground
Chat list panel (ChatListPanel.tsx):
- Folder header: expanded uses FolderOpenIcon, collapsed uses Folder01Icon
- Add tooltip showing full working directory path on folder hover
- Double-click folder header opens in system file manager
Title bar folder name (chat/[id]/page.tsx):
- Add tooltip with full path on project name hover
- Click opens folder in Finder/Explorer via Electron IPC or API fallback
Open folder support:
- electron/main.ts: add shell:open-path IPC handler via shell.openPath
- electron/preload.ts: expose electronAPI.shell.openPath to renderer
- api/files/open/route.ts: fallback API route using open/explorer/xdg-open
Unify icon library — migrate app-level components from Lucide to Hugeicons:
- file-tree.tsx: folder, file, chevron, plus icons
- tool-actions-group.tsx: chevron expand icon
- MessageItem.tsx: copy, check, expand/collapse icons
- MessageInput.tsx: stop button (SquareIcon → StopIcon)
- FileCard.tsx: file icon
- ImageLightbox.tsx: left/right navigation arrows
- InstallWizard.tsx: status icons (check, x, minus, loader, circle, copy, download)
- Keep Lucide in ui/ and ai-elements/ base layers (shadcn standard)
Core fixes:
- Add settingSources to SDK options so CodePilot loads user/project settings
like the CLI (fixes WebFetch timeouts, tool permission issues)
- Delete CLAUDECODE env var to prevent nested session detection when
CodePilot runs alongside Claude Code CLI (fixes 'exited with code 1')
- Remove manual MCP config reading (SDK handles it via settingSources)
- Remove hardcoded timeout env vars (SDK loads from user settings)
UX improvements:
- Remember last selected model across sessions (localStorage)
- Same-project new chat skips directory picker
- File tree auto-refreshes on project switch and after each tool completes
- Left sidebar projects default collapsed (only most recent expanded)
- Right-side file tree defaults collapsed
- Fix file tree icon alignment (spacer size-4 → size-5)
- Dynamic model list from /api/providers/models endpoint
- Provider change dispatches event to refresh model selector
- Improved error messages with provider name and troubleshooting hints
- Fix context button file type matching for extension patterns
- Default tool timeout 120s → 300s
FileTree component was not passing baseDir to the file API, causing
it to fall back to restricting access to the home directory. On
Windows, projects on a different drive (e.g., D:\) were blocked
with 403.
Changes:
- FileTree now passes workingDirectory as baseDir parameter
- File API routes no longer require baseDir to be under homeDir
(allows cross-drive access on Windows)
- Still prevents using filesystem root as baseDir for safety
- Add isRootPath() utility for root path detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The chat route and claude-client both fell back to process.cwd() when
working_directory was empty, causing Claude to operate in the server's
directory instead of the user's project. Since session creation now
requires a valid working_directory, these fallbacks are unnecessary
and misleading. Fall back to os.homedir() as a safer last resort.
Also update CLAUDE.md: require explicit user confirmation before
publishing releases (no auto push+tag).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v0.10.7 skipped .cmd wrappers entirely, but the SDK's internal
fallback can't find the CLI either. Now we read the .cmd file,
extract the actual .js path (e.g. node_modules/@anthropic-ai/
claude-code/cli.js), resolve %~dp0 to the wrapper's directory,
and pass the resolved script path to the SDK.
Regex patterns are scoped to paths containing "claude" to avoid
matching unrelated .js files in the wrapper.
Bump version to 0.10.8.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two root causes of spawn EINVAL on Windows:
1. process.env spread can include undefined values. Windows
child_process.spawn requires all env values to be strings.
sanitizeEnv now builds a clean object, dropping non-string entries.
2. Claude CLI installed via npm creates .cmd wrappers that cannot be
spawned without shell:true. Detect .cmd/.bat extensions and fall
back to SDK's internal resolution instead.
Bump version to 0.10.7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip null bytes and control characters from environment variable values
before passing them to child_process.spawn via the SDK. Third-party
Anthropic API providers could introduce invalid characters through
api_key, base_url, or extra_env, causing spawn EINVAL errors.
Bump version to 0.10.6.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Backend: POST /api/chat/sessions now validates working_directory
exists (400 MISSING_DIRECTORY / INVALID_DIRECTORY)
- db.ts: remove process.cwd() fallback in createSession
- ChatListPanel: validate last-working-directory before use,
open FolderPicker when invalid; add SSR guard for localStorage
- NewChatPage: block sending without a project directory selected
Bump version to 0.10.5.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- platform.ts: only cache positive findClaudeBinary results so a fresh
CLI install is detected immediately on next check
- ChatView.tsx: use useRef as atomic lock to prevent double-fetch from
rapid clicks on "Load earlier messages"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all readFileSync/existsSync/readdirSync with fs.promises
equivalents to unblock the Node event loop under concurrency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upload route now passes persisted filePath to claude-client, which
reuses it instead of writing the file again.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude CLI stores user-scoped MCP servers in ~/.claude.json, while
CodePilot was only reading from ~/.claude/settings.json. Now both
the MCP list API and streamClaude merge configs from both sources.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add configurable tool timeout with auto-retry: when a tool exceeds the
timeout threshold, abort and send a follow-up message asking Claude to
try a different approach
- Add "+" button on file tree items to attach files directly to chat
input via new /api/files/raw endpoint and custom event bridge
- Add force stop button in streaming status bar when tool runs >90s,
with warning indicators at 60s
- Improve doc preview markdown rendering (padding, list indentation)
- Bump version to 0.10.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add automatic update detection (checks GitHub Releases every 8h with
dialog prompt and blue dot on Settings icon) and a skip-permissions
toggle in Settings that uses the SDK's native bypassPermissions mode
to auto-approve all tool actions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Images were being saved to disk and referenced by text path in the prompt,
causing Claude to hallucinate about image contents since it never actually
saw the image data. Now images are sent as base64 content blocks via the
SDK's multimodal SDKUserMessage, enabling Claude's vision capability.
Non-image files continue to be saved to disk for Read tool access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Include base64 data in file metadata for chat display (fixes broken images)
- Use file-to-disk + Read tool approach instead of SDK multimodal
messages (fixes slow response caused by invalid prompt format)
- Move attach button before folder picker in input toolbar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ability to browse and import conversation history from Claude Code CLI
into CodePilot, with full resume support via SDK session ID.
Features:
- JSONL parser for Claude Code session files (~/.claude/projects/)
- REST API: GET /api/claude-sessions (list) + POST /api/claude-sessions/import
- Import dialog UI accessible from sidebar 'Import CLI Session' button
- Imported sessions bind sdk_session_id for seamless resume in CodePilot
- Duplicate import protection (409 with redirect to existing session)
- File size guard (50MB max) to prevent memory issues
Files changed:
- src/lib/claude-session-parser.ts — JSONL parser core
- src/app/api/claude-sessions/route.ts — list API
- src/app/api/claude-sessions/import/route.ts — import API with dedup
- src/components/layout/ImportSessionDialog.tsx — browse & import UI
- src/components/layout/ChatListPanel.tsx — sidebar integration
- src/__tests__/unit/claude-session-parser.test.ts — 17 unit tests
The SQLite database connection was never explicitly closed when the
process exits. In WAL mode, this can leave behind -wal and -shm files
and risk data loss if the WAL hasn't been checkpointed.
Changes:
- Add closeDb() export for explicit database closure
- Register process shutdown handlers (exit, SIGTERM, SIGINT, SIGHUP)
that call closeDb() before the process terminates
- Idempotent: multiple calls to closeDb() are safe
- After closeDb(), getDb() transparently re-opens the database
- Add 6 unit tests covering close, idempotency, reopen, data
persistence, and WAL cleanup (all passing)
- Support image (JPEG/PNG/GIF/WebP, max 5MB) and document uploads
- Images sent as multimodal content blocks to Claude SDK
- Documents saved to temp dir for Claude's Read tool
- Emerald capsule badges in input for attached files
- Drag-and-drop, paste, and file picker support via PromptInput
- Chat display: image thumbnails with lightbox, file cards
- Lightbox uses Radix Dialog with prev/next navigation
- File metadata embedded in message content as HTML comments
- Compatible with existing slash command badge system
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add findGitBash() to platform.ts that checks env var, common install
paths, and derives path from `where git`. Used in claude-client.ts
to set CLAUDE_CODE_GIT_BASH_PATH when not already configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Slash commands:
- Fix skills not appearing (removed non-existent `enabled` filter)
- Add badge/capsule UI for prompt-type commands (/compact, /review, etc.)
- SDK-native commands sent directly; CLI-only commands expanded to prompts
- /clear now resets SDK session and clears database messages
- /cost shows actual aggregated token usage statistics
- Keyboard: Backspace/Escape to remove badge, arrow keys auto-scroll popover
- Add /memory command for editing CLAUDE.md
Multi-provider management:
- CRUD API for API providers with SQLite storage
- ProviderManager UI with quick presets (GLM, Kimi, MiniMax, etc.)
- Dynamic model labels based on active provider
- Environment variable injection with conflict resolution
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The toSdkMcpConfig() function only handled stdio transport, discarding
the type, url, and headers fields. This meant SSE and HTTP MCP servers
configured through the Extensions page were silently converted to
broken stdio configs.
Changes:
- Import McpSSEServerConfig, McpHttpServerConfig, McpServerConfig types
from the Claude Agent SDK
- Rewrite toSdkMcpConfig() to dispatch on config.type (stdio/sse/http)
- SSE configs: pass type, url, and optional headers to the SDK
- HTTP configs: pass type, url, and optional headers to the SDK
- stdio configs: pass command, args, env (unchanged behavior)
- Skip servers with missing required fields (url for SSE/HTTP, command
for stdio) with a console warning instead of passing broken configs
- Do not include empty headers objects
- Add 11 unit tests covering all transport types, mixed configs,
missing fields, and edge cases (all passing)
This aligns the implementation with the README which states:
'Supports stdio, sse, and http transport types.'
- Fix Windows Claude CLI not found when installed as .exe or without
extension in .local\bin (closes#6). Now searches all extensions
(.cmd, .exe, .bat, and bare) for every candidate directory.
- Fix Extensions/Skills list not scrollable when many items exist.
Change content container to overflow-hidden so internal ScrollArea
works correctly. Add overflow-auto to McpManager for its own scroll.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add src/lib/platform.ts: cross-platform Claude CLI discovery
(candidate paths, .cmd/.bat shell handling, where/which fallback)
- Refactor claude-status route and claude-client to use shared platform utils
- Electron main: Windows process spawning (windowsHide), PATH construction
with AppData/npm dirs, titleBarOverlay, .ico icon support
- electron-builder.yml: add win/nsis build targets
- package.json: add electron:pack:win script
- FolderPicker: drive switcher dropdown for navigating between drives
- SkillsManager: fix duplicate key warning with filePath fallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously the database path depended on app.getPath('userData') which
varies with app name changes (CodePilot vs codepilot vs Claude GUI).
Now uses a fixed ~/.codepilot/ directory for both dev and production.
Includes automatic migration: on first launch, if the DB doesn't exist
at the new path, it checks old locations (Application Support variants
and the old dev-mode data/ folder) and copies the database over.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Skills API: accept optional cwd query param so project-level skills
are scanned from the session's working directory, not the standalone
server's process.cwd().
2. SDK env: explicitly set HOME so Claude Code can resolve ~/.claude/
for global skills discovery in packaged builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Change StickToBottom resize mode from "smooth" to "instant" to
prevent scroll position bouncing when new streaming content
arrives faster than the smooth animation completes.
2. Use SDK's preset append mode for system prompts instead of
replacing Claude Code's default prompt. This preserves Claude
Code's built-in awareness of skills (.claude/commands/), working
directory context, and other default behaviors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a new "API Configuration" section in settings for users who use
custom Anthropic-compatible APIs (e.g. via ai-claude-start). Users
can optionally set ANTHROPIC_AUTH_TOKEN and ANTHROPIC_BASE_URL in
CodePilot's settings UI. These are stored in SQLite and injected
into the Claude Code subprocess env only when configured.
Existing authentication methods (claude login, shell env vars) are
not affected - the API config is purely additive.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Explicitly pass process.env to the Claude Agent SDK's env option,
ensuring user shell env vars (ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL,
etc.) reach the claude subprocess in packaged builds.
2. Spawn the standalone server via /bin/sh with exec to prevent the
Electron binary from appearing as a separate Dock icon on macOS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SDK's query() function also needs to find the claude binary.
Added findClaudePath() in claude-client.ts and pass it via
pathToClaudeCodeExecutable option, fixing "Failed to create session"
in packaged builds where PATH is limited.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full-featured desktop application built with Next.js + Electron:
- Streaming chat with Claude Code via Agent SDK
- Session management with SQLite persistence
- Project file tree and file preview
- MCP server and custom skills management
- Permission controls with Code/Plan/Ask modes
- Dark/light theme, token tracking
- macOS DMG packaging with electron-builder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>