Commit Graph
26 Commits
Author SHA1 Message Date
7418andClaude Opus 4.6 ad34fe387b chore: 禁用 native auto-updater,改为引导用户从 GitHub 下载
macOS 上 ad-hoc 签名无法通过 ShipIt 的 kSecCSStrictValidate 校验,
导致热更新始终失败。在获取 Apple 开发者证书之前,暂时禁用 native
auto-updater,改为 browser-mode 检查 GitHub Releases API:

- electron/updater.ts: 注释掉 electron-updater 逻辑,initAutoUpdater
  和 setUpdaterWindow 改为 no-op
- electron/preload.ts: 注释掉 updater IPC bridge,前端不再暴露
  window.electronAPI.updater
- AppShell.tsx: isNativeUpdater 硬编码为 false,移除 native IPC 订阅
  和 native check/download/quitAndInstall 逻辑;保留 browser-mode
  的 GitHub API 检查(mount 时 + 每 8 小时),发现新版本时弹窗引导
  用户跳转 GitHub Release 页面下载

设置页 UpdateCard 保持不变:「检查更新」按钮通过 /api/app/updates
查询 GitHub,有新版本时显示「查看发布」按钮跳转下载。

TODO: 获取 Apple 开发者证书后,取消注释恢复 native auto-updater。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 11:45:36 +08:00
7418andClaude Opus 4.6 d13a0396f9 fix: replace tarball fallback with Homebrew install guide for macOS without brew
- electron/main.ts: check-prerequisites now returns hasHomebrew + platform
  so the frontend can distinguish macOS-without-Homebrew from other scenarios
- electron/main.ts: remove untested tarball fallback (hardcoded Node version,
  custom ~/.codepilot/node/bin PATH), replace with clean Homebrew-only path
  that returns a clear error message when Homebrew is absent
- electron/main.ts: remove ~/.codepilot/node/bin from getExpandedShellPath()
  since the tarball install target no longer exists
- InstallWizard.tsx: when Node.js is missing AND Homebrew is absent on macOS,
  show a guided UI with the Homebrew install command, copy button, and
  step-by-step instructions instead of a broken "Install" button
- InstallWizard.tsx: footer shows "Recheck" button (re-runs checkPrereqs)
  instead of "Install" in the no-Homebrew case
- en.ts/zh.ts: add 8 new i18n keys for the Homebrew guidance UI

Root cause: the previous tarball fallback was untested, pinned to a specific
Node version (v22.12.0), and required maintaining a custom PATH entry. Guiding
users to install Homebrew first is more reliable and maintainable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:30:32 +08:00
7418andClaude Opus 4.6 7fa10cd954 fix: macOS Node.js install fallback when Homebrew is unavailable, bump v0.17.6
Problem:
- Install wizard on macOS failed with "Homebrew not found" when user
  didn't have Homebrew installed, blocking Claude Code installation entirely

Fix (electron/main.ts):
- Add fallback: when Homebrew is not found, download official Node.js v22.12.0
  binary tarball from nodejs.org and extract to ~/.codepilot/node/
- No Homebrew or sudo required — curl + tar only
- Detects architecture (arm64/x64) via process.arch
- Add ~/.codepilot/node/bin to getExpandedShellPath() so the downloaded
  Node.js is found by subsequent install steps and server launcher

Install flow now: Homebrew found → brew install node (existing)
                  Homebrew missing → download tarball to ~/.codepilot/node/ (new)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:17:53 +08:00
7418andClaude Opus 4.6 132fdeb255 perf: P0 performance optimizations — memo, base64 cleanup, startup speed, bump v0.17.5
Six independent fixes targeting startup lag, streaming jank, and excessive payloads:

Step 0 — MessageItem React.memo + useMemo (MessageItem.tsx)
- Wrap MessageItem with React.memo so historical messages skip re-render
  when `message` ref is stable during streaming
- Add useMemo for parseToolBlocks + pairTools (deps: message.content),
  parseMessageFiles (deps: text), token_usage JSON.parse (deps: message.token_usage)
- Extract assistant content rendering into separate memo'd AssistantContent component
  to cache parseBatchPlan / parseImageGen chain (deps: displayText, messageId)
- Root cause: 50 msgs × 10 SSE events/s = 500 full parses/s causing UI jank

Step 1 — Strip base64 from new messages (ChatView.tsx, route.ts)
- ChatView: remove `data: f.data` from fileMeta in display content HTML comment
- route.ts: skip base64 data in fileAttachments when filePath exists (file already on disk)
- Root cause: base64 image data inflated message content to MB-level

Step 2 — Sanitize old messages in API (messages/route.ts)
- Add stripFileData() to strip base64 `data` fields from <!--files:...--> comments
  before returning messages from GET /api/chat/sessions/:id/messages
- Handles legacy data already stored with base64

Step 3 — Reduce initial fetch limit 100 → 30 (page.tsx, messages/route.ts)
- Default limit changed from 100 to 30 on both frontend and backend
- "Load more" functionality unchanged

Step 4 — ChatListPanel dedup requests (ChatListPanel.tsx)
- Remove duplicate pathname-dependent useEffect (was causing 2 fetches per navigation)
- Add AbortController to cancel in-flight requests on new fetch
- Add 300ms debounce for event-driven fetches (session-created/session-updated)

Step 5 — Electron startup: show window before server ready (electron/main.ts)
- createWindow() now accepts optional URL, defaults to inline loading HTML
- Loading page: dark theme, centered spinner, "Starting CodePilot..." text
- Startup: startServer() → createWindow(loading) → waitForServer() → loadURL(real)
- Also updated activate handler for same early-window pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:00:03 +08:00
7418andClaude Opus 4.6 09908cfcb7 fix: resolve macOS build race condition and update download button unresponsive
CI 修复 (electron-builder.yml):
- 移除 mac target 的 arch: [arm64, x64],改由 CI matrix 的 --arch flag 控制
- 根因:两个 macOS job 各自构建两个架构的 DMG,产生两个 draft release,
  导致 release job 只发布了没有 DMG 的那个,macOS 产物丢失

下载按钮无响应修复:
- electron/updater.ts: downloadUpdate IPC handler 加 try-catch,
  失败时通过 sendStatus 发送 error 事件给前端,避免静默失败
- AppShell.tsx: downloadUpdate 回调点击后立即设置 downloadProgress=0
  提供即时 UI 反馈;加 await + catch 处理下载失败并重置状态
- AppShell.tsx: error 事件处理中重置 downloadProgress 为 null,
  使下载按钮在失败后重新出现
- UpdateDialog.tsx / GeneralSection.tsx: isDownloading 判断移除 > 0 条件,
  downloadProgress === 0 时也显示下载中状态,消除点击后无反馈的间隙

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:11:20 +08:00
7418andClaude Opus 4.6 fd03d179e3 fix: improve auto-update UX and proxy support, bump v0.17.1
Auto-update flow rework:
- updater.ts: disable autoDownload, add manual `updater:download` IPC handler
  so user explicitly triggers download via "Download & Install" button
- updater.ts: resolve system proxy via session.defaultSession.resolveProxy()
  and inject into HTTPS_PROXY env var, fixing zero download speed behind VPN/proxy
- preload.ts + electron.d.ts: expose `downloadUpdate` method to renderer

UI improvements:
- UpdateDialog: add "Download & Install" button when update available but not
  yet downloading; show progress bar during download; "Restart to Update" when ready
- GeneralSection UpdateCard: show "Download & Install" / "Restart to Update" button
  next to "Check for Updates"; show download progress bar inline; add "View Details"
  link to reopen update dialog
- AppShell: dismissUpdate no longer permanently hides update for that version
  (removed localStorage persistence), just closes the dialog
- useUpdate: add downloadUpdate to context

i18n:
- Added `update.installUpdate` key (en: "Download & Install", zh: "下载并安装")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:19:48 +08:00
7418andClaude Opus 4.6 762953b2ad feat: integrate electron-updater for in-app auto-update
Replace the manual "jump to GitHub Release" update flow with native
in-app auto-update powered by electron-updater. The app now silently
downloads updates in the background and prompts the user to restart
when ready. Browser mode (`npm run dev`) retains the existing polling
fallback via `/api/app/updates`.

Main process (electron/updater.ts — new):
- Wrap electron-updater's autoUpdater, forward lifecycle events
  (checking / available / downloading / downloaded / error) to the
  renderer via IPC channel `updater:status`
- Register `updater:check` and `updater:quit-and-install` IPC handlers
- Auto-check 10s after launch, then every 4 hours
- Only initialized in packaged mode (!isDev)

Preload bridge (electron/preload.ts):
- Expose `updater` namespace with checkForUpdates, quitAndInstall,
  and onStatus callback (same pattern as install.onProgress)

Type declarations (src/types/electron.d.ts):
- Add UpdateStatusEvent, ElectronUpdaterAPI interfaces
- Add optional `updater` field to ElectronAPI

Update hook (src/hooks/useUpdate.ts):
- Extend UpdateInfo with downloadProgress, readyToInstall, isNativeUpdate
- Add quitAndInstall to UpdateContextValue

Renderer — dual-mode logic (src/components/layout/AppShell.tsx):
- Detect `window.electronAPI?.updater` to choose between native IPC
  subscription (Electron) and HTTP polling (browser)
- Map IPC events to UpdateInfo state, including download progress

UI components:
- UpdateDialog: three footer states — View Release (browser), progress
  bar + disabled button (downloading), Restart to Update (ready)
- UpdateBanner (new): persistent top banner when update is downloaded,
  shown even after dialog is dismissed
- NavRail: settings dot turns green + pulse when readyToInstall
- GeneralSection: UpdateCard shows download %, restart button, or
  View Release depending on mode

Build & CI:
- electron-builder.yml: add `publish` config (github provider) to
  generate latest-mac.yml / latest.yml metadata + blockmap files
- build.yml: change --publish never to --publish always with GH_TOKEN;
  release job now uses `gh release edit` instead of create

i18n:
- Add 6 translation keys (en + zh) for update UI strings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:16:41 +08:00
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
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
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 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 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 21ca106720 fix: graceful server shutdown with SIGKILL fallback
Add killServer() that sends SIGTERM via UtilityProcess.kill(), waits
up to 3s, then escalates to SIGKILL via process.kill(pid). Fixes
window-all-closed to await shutdown before quitting, and uses a
persistent isQuitting flag in before-quit to prevent infinite loops.

Closes #51

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 22:55:04 +08:00
7418andClaude Opus 4.6 de7b211876 fix: use utilityProcess.fork() to prevent macOS Dock bouncing icon
Replace child_process.spawn with Electron's utilityProcess.fork() for
the Next.js server subprocess. utilityProcess runs as a Chromium
service process which doesn't register as a GUI app, eliminating the
extra Dock icon bounce on macOS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 21:02:33 +08:00
liuxiaopai-ai afeaa6a120 feat: add Linux build support (AppImage, deb, rpm)
Add Linux as a supported platform with AppImage, deb, and rpm targets
for both x64 and arm64 architectures.

Changes:
- electron-builder.yml: add linux section with AppImage/deb/rpm targets,
  icon, category, and desktop entry configuration
- package.json: add electron:pack:linux script
- electron/main.ts: fix getIconPath() to return .png on Linux instead
  of .icns (macOS format); enable loadUserShellEnv() on Linux since GUI
  apps launched from desktop also have limited env
- README.md + README_CN.md: update supported platforms section

The README previously stated 'Linux builds are planned. Contributions
welcome.' — this delivers on that.
2026-02-08 16:01:33 +08:00
7418andClaude Opus 4.6 b42d3d2ad8 fix: explicitly rebuild better-sqlite3 for Electron ABI in afterPack
Root cause: electron-builder's @electron/rebuild only rebuilds native
modules found in the `files` config. Since better-sqlite3 enters the
app through extraResources (via .next/standalone/), it was skipped.
The afterPack hook was copying the system Node.js ABI (127) instead
of the required Electron ABI (143).

Fix:
- afterPack now explicitly calls `npx electron-rebuild` targeting the
  exact Electron version and architecture from the build context
- Falls back to @electron/rebuild programmatic API if CLI fails
- Fails the build if rebuild cannot complete (no silent failures)
- Adds file size logging for verification
- Excludes `release/` from extraResources to prevent recursive nesting
- Adds startup ABI compatibility check in Electron main process with
  friendly error dialog instead of cryptic crash

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 16:23:37 +08:00
xuxu777xuandClaude Opus 4.6 0234240066 feat: full Windows platform adaptation
- 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>
2026-02-07 13:35:04 +08:00
7418andClaude Opus 4.6 262b295f63 fix: use stable ~/.codepilot/ data directory to persist across updates
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>
2026-02-07 13:07:08 +08:00
7418andClaude Opus 4.6 e4ae2154af fix: pass env to SDK subprocess and hide server Dock icon
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>
2026-02-06 23:06:52 +08:00
7418andClaude Opus 4.6 185e138833 fix: load user shell env for API keys in packaged Electron app
When launched from Dock/Finder, Electron's process.env is very limited
and misses vars from .zshrc/.bashrc (API keys, custom PATH, etc.).
Added loadUserShellEnv() to run a login shell and capture the full
environment, then pass it to the standalone server process. This fixes
"organization does not have access" errors for users with custom API
configurations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 22:50:19 +08:00
7418andClaude Opus 4.6 e565d873f9 fix: use Electron's Node.js for standalone server to match ABI
electron-builder's @electron/rebuild compiles better-sqlite3 for
Electron's Node ABI. The standalone server must use Electron's
built-in Node (ELECTRON_RUN_AS_NODE=1) to match, otherwise the
native module fails with NODE_MODULE_VERSION mismatch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 22:40:24 +08:00
7418andClaude Opus 4.6 37e5e4ed71 fix: use system Node.js for standalone server, improve error reporting
- Find system Node.js binary instead of using Electron's Node
  (avoids native module ABI mismatch with better-sqlite3)
- Detect server process crash and fail fast instead of waiting 30s
- Include server stdout/stderr in error dialog for debugging
- Expand PATH to include homebrew directories

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 21:39:41 +08:00
7418andClaude Opus 4.6 2f40bd2c62 fix: use spawn with ELECTRON_RUN_AS_NODE for packaged server
- Replace fork() with spawn() + ELECTRON_RUN_AS_NODE=1 so the
  standalone server runs correctly inside the packaged app
- Set cwd to standalone directory for proper dependency resolution
- Show error dialog on startup failure instead of silent quit
- Add Chinese README (README_CN.md)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 21:33:27 +08:00
7418andClaude Opus 4.6 ff1fb38735 feat: CodePilot - desktop GUI for Claude Code
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>
2026-02-06 21:04:05 +08:00