Commit Graph
156 Commits
Author SHA1 Message Date
7418andClaude Opus 4.6 c6ed594800 feat: use native OS folder picker dialog in Electron mode
Electron 环境下改用系统原生文件夹选择对话框替代自定义 FolderPicker 组件,
浏览器环境保留原有 FolderPicker 作为 fallback(浏览器沙箱无法获取绝对路径)。

- electron/main.ts: 新增 `dialog:open-folder` IPC handler,调用
  `dialog.showOpenDialog` 并设置 openDirectory + createDirectory 属性,
  macOS 下支持在对话框内新建文件夹,对话框模态绑定 mainWindow
- electron/preload.ts: 在 electronAPI 中暴露 `dialog.openFolder()` 方法
- src/types/electron.d.ts: 新建全局类型声明,统一定义 window.electronAPI
  的完整类型,消除代码中散落的 `(window as any)` 类型断言
- src/hooks/useNativeFolderPicker.ts: 新建 hook 封装平台检测和原生对话框
  调用逻辑,返回 isElectron 标志和 openNativePicker 方法
- src/components/layout/ChatListPanel.tsx: 新增 openFolderPicker() 统一入口,
  Electron 走原生对话框、浏览器走 setFolderPickerOpen(true);替换
  handleNewChat 中 4 处及文件夹按钮 onClick 共 5 处调用点;
  handleFolderSelect 改为 useCallback 并调整声明顺序避免引用前使用;
  清理 electronAPI 类型断言
- src/app/chat/[id]/page.tsx: 移除 `window as unknown as ...` 类型断言
- src/components/layout/ConnectionStatus.tsx: 移除 `(window as any)` 断言
- src/components/layout/InstallWizard.tsx: getInstallAPI() 简化为直接返回
  window.electronAPI?.install,移除 10 行手动类型定义

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:47:08 +08:00
7418andClaude Opus 4.6 5bace38e47 fix: improve ErrorBoundary i18n and update provider preset descriptions
ErrorBoundary (PR #49 follow-up):
- Replace inline SVG with lucide-react CircleAlert icon for consistency
- Add i18n support: extract fallback UI into functional ErrorFallback
  component so it can use useTranslation hook
- Remove unused withErrorBoundary HOC
- Add error.* translation keys to en.ts and zh.ts

ProviderManager:
- Add Claude Code default config entry in connected providers section
  with cc switch hint explaining configurations may not be readable
- Update GLM preset descriptions: "GLM" → "GLM Code Plan / 编程套餐"
- Update MiniMax preset descriptions: "MiniMax API" → "MiniMax Code Plan / 编程套餐"
- Add provider.ccSwitchHint translation key to en.ts and zh.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:34:42 +08:00
歸藏 cd807ef175 Merge pull request #49 from cyxer000/feat/error-boundary
Error Boundary for crash isolation. Minor fixes (i18n, icon, h-5 conflict) will follow.
2026-02-26 10:23:24 +08:00
歸藏 791baff5b9 Merge pull request #101 from Earl-chen/docs/fix-electron-dev-instructions
Clean docs fix — adds missing electron build step
2026-02-26 10:23:14 +08:00
7418andClaude Opus 4.6 d203b9802d feat: redesign Provider settings UI with brand icons and dialog-based quick-add
Completely rewrites the Provider management page in Settings to follow
the OpenCode reference design with two clear sections.

ProviderManager.tsx — full rewrite:
- Top section "Connected Providers": shows all configured providers as a
  clean list with brand icons from @lobehub/icons, name, badge, edit and
  disconnect buttons. Environment variables also shown here.
- Bottom section "Add Provider": preset list with icon + name + description
  + Connect button. Clicking Connect opens a dialog with only the fields
  needed for that preset.
- First 3 presets: Custom API (all fields), Anthropic Third-party API
  (name + URL + key), Anthropic Official (key only).
- Other presets (GLM, Kimi, Moonshot, MiniMax, etc.) simplified to key-only.
- Bedrock/Vertex show environment variable config.
- Removed the top-right "Add Provider" button entirely.
- Added PresetConnectDialog component: shows brand icon in title, only
  relevant fields, advanced options fold for extra_env, Cancel/Connect footer.

package.json:
- Add @lobehub/icons dependency for AI brand icons
- Bump version to 0.15.0

i18n (en.ts, zh.ts):
- Add translations: connectedProviders, noConnected, connect, disconnect,
  disconnectProvider, disconnectConfirm, addProviderSection, addProviderDesc,
  disconnecting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:48:23 +08:00
7418andClaude Opus 4.6 448738d4f3 feat: provider/model system refactor — switch provider from chat input
Refactors the provider/model selection system so users can switch providers
directly from the chat input model selector, instead of having to go to
Settings to activate/deactivate providers.

types/index.ts:
- Add ProviderModelGroup interface for grouped provider+model data
- Extend SendMessageRequest, ClaudeStreamOptions, ChatSession with provider_id

db.ts:
- Migration: add provider_id column to chat_sessions
- Migration: convert is_active=1 provider to default_provider_id setting
- New helpers: updateSessionProviderId, getDefaultProviderId, setDefaultProviderId

providers/models/route.ts:
- Rewrite to return { groups, default_provider_id } instead of flat model list
- Each configured provider becomes a group; env vars become "Environment" group
- Deduplicate models within a group (e.g. GLM sonnet/opus both → "GLM-4.7" once)

chat/route.ts:
- Accept provider_id from request body
- Resolution chain: request → session → default_provider_id → env vars
- provider_id='env' is sentinel for environment variable fallback
- Pass resolved provider object to streamClaude()

claude-client.ts:
- Use options.provider ?? getActiveProvider() so explicit provider takes priority

ChatView.tsx:
- Track currentProviderId state, pass provider_id in fetch body
- New handleProviderModelChange callback

MessageInput.tsx:
- New props: providerId, onProviderModelChange
- Replace dynamicModels/activeProviderName with providerGroups/defaultProviderId
- Model selector UI: grouped by provider with section headers, ✓ for active item
- Persist both model and provider ID to localStorage

chat/page.tsx, chat/[id]/page.tsx:
- Track and pass provider_id through the component chain

ProviderManager.tsx:
- Remove handleActivate/handleDeactivate, activatingId, Apply/Disable buttons
- Remove Active badge and green border styling
- Simplify env variable banner
- Add provider-changed event dispatch to save/delete handlers

providers/route.ts:
- GET response now includes default_provider_id field

i18n (en.ts, zh.ts):
- Add provider.default, provider.setDefault, provider.environment translations

Backward compatible: old sessions without provider_id default to '' which
triggers the fallback chain. is_active column preserved but no longer written.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:22:18 +08:00
7418andClaude Opus 4.6 cf14791de0 fix: abort active stream on session switch and warn before closing during streaming
- Add useEffect cleanup to abort in-flight fetch when ChatView unmounts
  (e.g., session switch via key={id} remount). This triggers the existing
  server-side cleanup chain: saves partial message to DB, auto-denies
  pending permissions. Also resets streamingSessionId and
  pendingApprovalSessionId global state to prevent stale UI.

- Add beforeunload handler during streaming to show browser confirmation
  dialog when user attempts to close the window/tab, preventing accidental
  data loss. Listener is automatically removed when streaming ends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:33:51 +08:00
7418andClaude Opus 4.6 fa1023c483 feat: add AI semantic search for skill matching in / command popover
- New API route: src/app/api/skills/search/route.ts
  - POST endpoint receives query + skill list + model alias
  - resolveApiConfig() resolves credentials: active provider → settings → env
  - Supports Anthropic direct, OpenRouter (Bearer auth), custom base URLs
  - Bedrock/Vertex silently return empty results (unsupported)
  - 5s hard timeout, all errors return { suggestions: [] }
  - LLM returns JSON array of matching skill names, validated against input

- Modified: src/components/chat/MessageInput.tsx
  - Extend substring matching to search both label and description fields
  - Add debounced AI search (500ms) when skill mode has < 2 non-built-in
    substring matches and filter length >= 2 characters
  - AbortController cancellation on new input or popover close
  - "AI Suggested" section with BrainIcon and spinner in popover UI
  - Unified keyboard navigation across filteredItems + aiSuggestions
    using allDisplayedItems for ArrowUp/Down, Enter/Tab, and visibility

- Modified: src/i18n/en.ts, src/i18n/zh.ts
  - Added 'messageInput.aiSuggested' translation key (EN/ZH)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:30:45 +08:00
chenming ac8984c82b docs: add missing electron build step before electron:dev
The `electron:dev` script requires `dist-electron/main.js` to exist,
but the README does not mention running `node scripts/build-electron.mjs`
beforehand. Without this step, `electron .` fails with:
  "Cannot find module '/path/to/dist-electron/main.js'"

Add the build command to both the Quick Start and Development sections
in all three README files (EN, CN, JA).
2026-02-25 11:21:39 +08:00
7418andClaude Opus 4.6 52f5bb5f86 feat: add token usage statistics page in Settings
New "Usage" tab in Settings showing token consumption analytics:

- **Data cards**: Total Tokens, Total Cost, Sessions, Cache Hit Rate
- **Bar chart**: Daily token usage with model/provider color grouping
  using recharts v3, with custom tooltip and continuous date x-axis
- **Provider tracking**: Each session now records the active provider
  name (e.g. "Kimi Coding Plan") so the chart distinguishes usage
  across different providers, not just model names

Backend changes (db.ts):
- Added `provider_name` column to chat_sessions with auto-migration
- Added `getTokenUsageStats(days)` with summary + daily aggregation
- SQL uses `json_valid()` guard to prevent malformed JSON crashes
- Fixed off-by-one: 7D now shows exactly 7 calendar days, not 8
- Provider-qualified grouping: shows provider name when set,
  plain model name when using direct Anthropic

API changes (route.ts):
- Persists effectiveModel and activeProvider name on every message
- Captures model from SDK init event for accurate tracking
- New GET /api/usage/stats endpoint

Frontend fixes:
- SettingsLayout: replaced useEffect+setState with useSyncExternalStore
  to fix react-hooks/set-state-in-effect lint error
- UsageStatsSection: AbortController prevents request race on rapid
  range switching; cache hit rate formula corrected to
  cache_read/(cache_read+input); date gaps filled with zeros for
  continuous x-axis
- Full i18n support (en + zh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 00:07:41 +08:00
7418andClaude Opus 4.6 edd55a9b0f fix: improve session resume resilience, permission timeout, and stream idle handling
1. Resume pre-check and degradation (claude-client.ts):
   - Check working_directory exists on disk before attempting resume;
     if missing, skip resume, clear sdk_session_id, notify frontend
   - On resume peek failure, clear sdk_session_id to prevent repeated
     retries on the same broken session
   - Change iterator wrap condition from sdkSessionId to shouldResume
     so skipped resumes don't enter the peek path

2. Per-request independent permission timeout (permission-registry.ts):
   - Replace lazy cleanup (cleanupExpired on next register) with a
     dedicated setTimeout per permission request
   - Auto-deny after 5 minutes with clearTimeout on resolve/abort
   - Extract denyAndRemove helper for abort and timeout paths

3. Permission wait visibility (StreamingMessage.tsx):
   - Always show StreamingStatusBar during streaming (remove
     !pendingPermission guard)
   - Display "Waiting for authorization: <tool>" with elapsed timer
     when a permission request is pending, instead of hiding the bar

4. Stream idle timeout (ChatView.tsx):
   - Add 330s idle timeout (slightly above 5-min permission timeout
     to avoid races) using setInterval that checks lastEventTime
   - Every SSE callback calls markActive() to reset the timer
   - On idle timeout, abort the stream and show a readable error
   - Clean up interval in both catch and finally blocks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 21:39:09 +08:00
7418 7b9de0ab23 fix: add detailed error logging for SDK process failures
The "exited with code 1" error was hiding the real cause. Now:
- Logs full error object to console (message, stack, cause, stderr)
- Extracts stderr/cause from SDK error and includes in user-facing message
- Adds "Details:" section to the error when extra info is available

This will help diagnose why old sessions fail on some machines while
new sessions work fine with the same provider config.

- src/lib/claude-client.ts: enhanced catch block with console.error
  logging and stderr/cause extraction for error messages
2026-02-24 18:10:39 +08:00
7418 959b2bde06 chore: bump version to 0.13.2 2026-02-24 17:57:39 +08:00
7418 f871087a84 fix: clear stale sdk_session_id on mid-stream crash to prevent repeated failures
When a resumed SDK session crashes mid-stream (after outputting some
content), the sdk_session_id remains in the database. Every subsequent
message in that chat session attempts to resume the same broken SDK
session, causing repeated failures.

Root cause: the SDK process starts successfully with resume, outputs
some content, then crashes (exit code 1). The sdk_session_id was
already stored from a previous successful turn and never gets cleared
on error.

Fix: in the catch block of streamClaude(), when we were resuming a
session (sdkSessionId is set), clear the sdk_session_id in the
database. This ensures the next message starts a fresh SDK session
instead of repeatedly hitting the same broken resume.

Combined with the earlier peek-based fallback (which handles failures
at startup), this covers both failure modes:
1. Resume fails immediately → fallback retries without resume in the
   same request
2. Resume fails mid-stream → clears sdk_session_id so the NEXT
   request starts fresh

- src/lib/claude-client.ts: import updateSdkSessionId, add
  sdk_session_id reset in catch block when sdkSessionId was set
2026-02-24 17:56:38 +08:00
7418 481f218474 chore: bump version to 0.13.1 2026-02-24 17:52:35 +08:00
7418 61e093094e fix: auto-fallback to fresh conversation when SDK session resume fails
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
2026-02-24 17:50:49 +08:00
7418 979e1b1973 fix: update Sonnet model label from 4.5 to 4.6
- src/app/api/providers/models/route.ts: updated DEFAULT_MODELS and
  OpenRouter provider mapping from "Sonnet 4.5" to "Sonnet 4.6"
- src/components/chat/MessageInput.tsx: updated DEFAULT_MODEL_OPTIONS
  fallback label from "Sonnet 4.5" to "Sonnet 4.6"
2026-02-24 17:14:44 +08:00
7418 c7c3ba5302 feat: v0.13.0 — add i18n support with Chinese/English translations
Implements a zero-dependency i18n framework with TypeScript type safety.
Thanks to @gy212 for the original i18n infrastructure design (PR #89)
and comprehensive translation files (PR #90-96) that inspired this implementation.

## New files (5)

- src/i18n/en.ts: English translations (source of truth, ~270 keys),
  exports TranslationKey type for compile-time key completeness
- src/i18n/zh.ts: Chinese translations, typed as Record<TranslationKey, string>
- src/i18n/index.ts: translate() function with {param} interpolation,
  Locale type, SUPPORTED_LOCALES array
- src/components/layout/I18nProvider.tsx: React Context provider,
  loads/persists locale preference via /api/settings/app
- src/hooks/useTranslation.ts: useTranslation() hook returning
  { locale, setLocale, t }

## Infrastructure wiring

- src/app/layout.tsx: I18nProvider wrapped inside ThemeProvider
- src/app/api/settings/app/route.ts: added "locale" to ALLOWED_KEYS
  for persistence

## Language picker

- src/components/settings/GeneralSection.tsx: added language selection
  dropdown (Select component) in Settings > General, using
  SUPPORTED_LOCALES and setLocale()

## String replacements (33 component files)

All hardcoded user-facing strings replaced with t() calls:

High priority (chat):
- ChatListPanel.tsx: session list, search, empty state, relative time
- NavRail.tsx: nav labels, theme toggle, auto-approve indicator
- MessageInput.tsx: command descriptions, mode labels, attach tooltip
- MessageList.tsx: empty state, load earlier, loading indicator
- StreamingMessage.tsx: thinking, permission actions
- chat/[id]/page.tsx: session title fallback

Settings:
- GeneralSection.tsx: update card, auto-approve section, warning dialog
- SettingsLayout.tsx: title, description, sidebar labels
- CliSettingsSection.tsx: form/json tabs, buttons, dynamic field labels
  (skipDangerousModePermissionPrompt etc.), Enabled/Disabled states
- ProviderForm.tsx: dialog title, form labels, buttons
- ProviderManager.tsx: status badges, delete dialog, section headers

Extensions:
- extensions/page.tsx: title, tab labels
- SkillsManager.tsx: empty state, loading, search
- SkillEditor.tsx: toolbar buttons, placeholder
- SkillListItem.tsx: delete confirmation
- CreateSkillDialog.tsx: form labels, scope, templates, validation

Plugins:
- McpManager.tsx: header, tabs, loading state
- McpServerList.tsx: empty state, badges, field labels
- McpServerEditor.tsx: dialog title, form labels, buttons
- ConfigEditor.tsx: save/format buttons

Layout:
- RightPanel.tsx: panel header, open/close tooltips
- FileTree.tsx: search placeholder, empty states
- FilePreview.tsx: back button, line count, copy path
- DocPreview.tsx: iframe title
- ConnectionStatus.tsx: install prompts, version display
- InstallWizard.tsx: phase descriptions, button labels
- ImportSessionDialog.tsx: search, relative time, import buttons
- FolderPicker.tsx: dialog title, loading, buttons
- TaskList.tsx: filter tabs, input placeholder, empty states
2026-02-24 16:50:57 +08:00
7418 85940dfde3 fix: align title bar headers across panels, fix macOS Dock icon size
Title bar alignment (AppShell.tsx, page.tsx, DocPreview.tsx):
- Reduce AppShell draggable spacer from h-11 to h-5 to match side panels' mt-5
- Chat title bar uses normal flow h-12 instead of absolute positioning hack
- DocPreview header changed from h-10 to h-12 mt-5
- All three columns now align at the same vertical position

macOS Dock icon (build/icon.png, build/icon.icns):
- Add 100px transparent padding on all sides (content 824x824 in 1024x1024 canvas)
- Follows Apple Human Interface Guidelines for macOS app icons
- Regenerated icon.icns with all required sizes
- Original icon backed up as icon-original.png

Remove start execution button (ChatView.tsx):
- Remove showStartExecution logic and handleStartExecution callback
- Mode switching is now handled automatically by SDK
2026-02-24 15:30:42 +08:00
7418 9e7ccfefaa feat: v0.12.0 — fix streaming tool UI persistence, file tree UX improvements, unify icon library
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)
2026-02-24 12:32:03 +08:00
cyxer000 11ece8df88 feat: add React Error Boundary to prevent UI white-screen crashes
Wrap main content area and chat list panel with ErrorBoundary
components to gracefully handle runtime errors instead of
showing a blank white screen.

Closes #32
2026-02-24 11:12:53 +08:00
7418 8ee8085930 docs: add commit message guidelines to CLAUDE.md
Add 'Commit 信息规范' section to Development Rules requiring:
- Conventional commits format in title
- Detailed per-file/per-feature change descriptions in body
- Root cause explanation for bug fixes
- Architectural decision rationale when applicable

Also remove v0.11.0 changelog that was mistakenly added to CLAUDE.md
(changelogs belong in commit messages and GitHub Releases, not here).
2026-02-24 03:10:53 +08:00
7418 9c13f043d0 feat: v0.11.0 — SDK settingSources, nested session fix, dynamic models, UX improvements
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
2026-02-24 03:08:17 +08:00
7418andClaude Opus 4.6 31879e0540 chore: bump version to 0.10.11
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:19:00 +08:00
7418andClaude Opus 4.6 8f963ed2a9 fix: pass baseDir to file preview API to fix Windows cross-drive 403
FilePreview and DocPreview components were not passing baseDir to
the preview API, causing 403 "File is outside the allowed scope"
on Windows when the project is on a different drive than home.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:13:06 +08:00
7418andClaude Opus 4.6 c21d8e4e90 fix: remove last process.cwd() fallback in file upload path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:06:49 +08:00
7418andClaude Opus 4.6 3fa3058b09 chore: bump version to 0.10.10
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:59:01 +08:00
7418andClaude Opus 4.6 332b62bbe0 fix: prevent uninstall from deleting user files and fix Windows process cleanup
Two fixes for critical Windows issues (#81):

1. NSIS installer: disable allowToChangeInstallationDirectory to prevent
   users from installing into shared directories where uninstall would
   delete all their files. Also set deleteAppDataOnUninstall: false to
   preserve user data.

2. Windows process cleanup: killServer() used SIGTERM which Windows
   doesn't support, leaving zombie processes that block updates.
   Now uses taskkill /T /F to kill the entire process tree on Windows,
   ensuring no residual processes remain after app exit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:56:40 +08:00
7418andClaude Opus 4.6 4472d21028 chore: bump version to 0.10.9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:36:21 +08:00
7418andClaude Opus 4.6 5dde1e5009 fix: folder picker dialog content overflow on narrow windows
- Add overflow-hidden to dialog to constrain child components
- Change path display from truncate to horizontal scroll so long
  Windows paths (e.g., D:\projects\very\deep\path) remain readable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:35:48 +08:00
7418andClaude Opus 4.6 d446da9717 fix: allow file tree access on Windows cross-drive project paths
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>
2026-02-13 17:33:06 +08:00
7418andClaude Opus 4.6 6aca8c3870 fix: remove process.cwd() fallback for working directory in chat route
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>
2026-02-13 17:28:53 +08:00
7418andClaude Opus 4.6 01e7e0c1e3 fix: parse Windows .cmd wrapper to extract real CLI script path
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>
2026-02-13 17:07:21 +08:00
7418andClaude Opus 4.6 c0e96bd1aa fix: resolve spawn EINVAL on Windows — filter undefined env values and skip .cmd wrappers
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>
2026-02-13 16:48:59 +08:00
7418andClaude Opus 4.6 83a0109af1 fix: sanitize env variables to prevent spawn EINVAL with third-party API providers
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>
2026-02-13 16:01:22 +08:00
7418andClaude Opus 4.6 916b8889b7 fix: require valid project directory for session creation
- 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>
2026-02-13 15:37:51 +08:00
7418andClaude Opus 4.6 ae8a905581 feat: inline title editing, simplify right panel, polish input toolbar
- Add inline title editing in chat header (hover to reveal pencil icon,
  click to edit, Enter/Blur to save, Escape to cancel)
- Simplify right panel: remove Name section, rename header to "Files"
- Align top headers across all three columns (left/center/right)
- Remove folder picker from message input (project already set via sidebar)
- Change attachment icon from paperclip to plus sign
- Remove icon from mode selector, move model selector next to mode selector
- Fix FileTree search icon alignment and left padding consistency
- Add background to chat list delete button to prevent text overlap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 15:23:36 +08:00
7418andClaude Opus 4.6 5a57098ffd feat: group chat sidebar by project folder with collapsible sections
Restructure the chat list panel to group sessions by working directory
(project folder), similar to Codex App. Each project folder is shown as
a collapsible section with a folder icon and project name. Features:

- Sessions grouped by working_directory, sorted by most recent activity
- Collapsible folder sections with persistent state in localStorage
- Per-folder "+" button to create new chat in that project
- "Open project folder" button in sidebar header with FolderPicker dialog
- NavRail new-chat button creates sessions in most recent project
- Chat header shows "projectName / sessionTitle" breadcrumb
- Search filters both folder names and session titles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:46:50 +08:00
7418andClaude Opus 4.6 d199cbec6c fix: file tree height cut off at half panel — fill remaining space
Remove hardcoded max-h-[400px] on tree content area. Convert the
right panel body and Files section to flex column layout so the
file tree expands to fill all available vertical space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:33:06 +08:00
7418andClaude Opus 4.6 27d19adba3 chore: bump version to 0.10.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:19:12 +08:00
7418andClaude Opus 4.6 572bd355f8 fix: require explicit user confirmation before install, cancel on close, tree-kill on Windows
P0: Add "confirm" phase — wizard checks prereqs then shows Install button,
    user must explicitly click before any brew/winget/npm command runs.
P1: Closing the wizard dialog while install is running now auto-calls
    install:cancel to stop the backend process.
P2: On Windows, use taskkill /T /F /PID to kill the entire process tree
    instead of just the shell wrapper, ensuring npm/winget actually stops.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:51:15 +08:00
7418andClaude Opus 4.6 51d4906c77 fix: address Codex review — Node auto-install, first-launch prompt, IPC consistency
P1: When Node.js is missing, auto-install via brew (macOS) or winget (Windows)
    instead of stopping and asking user to install manually.
P1: Auto-open install wizard on first disconnect detection in Electron,
    with localStorage flag to avoid re-prompting after dismissal.
P2: IPC install:start now throws on concurrent calls instead of returning
    silent { error } object. Removed unused return values from handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:33:54 +08:00
7418andClaude Opus 4.6 e4b917172c feat: add one-click Claude Code install wizard
Add an auto-install wizard accessible from the ConnectionStatus dialog
when Claude Code CLI is not detected (Electron only).

- Electron main: install orchestrator with IPC handlers for check/start/cancel
- Preload: expose install API via contextBridge
- InstallWizard: multi-step dialog with real-time log streaming
- ConnectionStatus: add "Install Automatically" button when disconnected

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:29:39 +08:00
7418andClaude Opus 4.6 23d05cabe1 fix: file tree attachment fails on non-home paths in packaged app
- Remove homedir-only restriction from /api/files/raw (desktop app
  doesn't need this sandbox, projects can be anywhere)
- Add console.warn on fetch failure instead of silent swallow
- Fix filename extraction for Windows backslash paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 13:01:54 +08:00
7418andClaude Opus 4.6 097bd2ad8a docs: remove "native" wording from README descriptions
Closes #74

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 11:13:35 +08:00
7418andClaude Opus 4.6 d2c6964fd8 fix: CI changelog echo breaks on special chars in commit messages
Use heredoc instead of single-quoted echo to write changelog into
release notes, preventing shell syntax errors from quotes/pipes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:47:43 +08:00
7418andClaude Opus 4.6 11565de083 chore: bump version to 0.10.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:37:20 +08:00
7418andClaude Opus 4.6 ccd687c8f5 fix: don't cache "not found" binary result, use ref lock for pagination
- 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>
2026-02-13 01:34:36 +08:00
7418andClaude Opus 4.6 9b166be8d6 fix: resolve 25 error-level lint issues (P1-3)
Fix no-require-imports, no-explicit-any, no-html-link-for-pages,
set-state-in-effect, purity, static-components, and refs rules
across 15 files. 0 errors remain (52 warnings unchanged).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:24:51 +08:00
7418andClaude Opus 4.6 e86f0cfd8f perf: optimize polling with caching and event-driven approach (P1-2)
- CLI binary detection cached with 60s TTL
- Settings poll replaced with visibility/focus events
- Health check uses adaptive backoff (30s → 60s when stable)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 01:24:43 +08:00