Commit Graph
32 Commits
Author SHA1 Message Date
7418andClaude Opus 4.6 c07a604271 fix: address code review findings — snapshot dedup, workspace hooks, permission params, Windows health check
ChatView.tsx (P2): snapshot consumption now calls detectAssistantCompletion()
so assistant workspace onboarding/check-in state updates even when the
stream completes while ChatView is unmounted.

ChatView.tsx (P2): replace local temp-message append with a DB re-fetch
on snapshot consumption to avoid duplicate messages (backend already
persists the reply in route.ts).

page.tsx (P3): add updatedInput and denyMessage parameters to
handlePermissionResponse so AskUserQuestion answers and ExitPlanMode
custom deny messages are forwarded to the permission API on the
first-message page.

electron/main.ts: fix Windows startup timeout by forcing IPv4 (family:4)
in health check HTTP request and improving error diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:24:19 +08:00
315aac0f04 fix: sanitize __NEXT_PRIVATE_* env vars from child processes (#161)
* fix: preserve paragraph breaks between text blocks in bridge responses

When Claude's response includes tool calls (Read, Edit, Bash, etc.),
the response text is split into multiple content blocks — one before
each tool call and one after. These blocks were joined with an empty
string (.join('')), causing all paragraphs to concatenate without
any spacing in the final Telegram message.

Changed .join('') to .join('\n\n') so paragraph breaks between text
blocks are preserved, matching how they appear in the desktop UI.

* fix: sanitize __NEXT_PRIVATE_* env vars from child processes

The bundled Next.js standalone server sets __NEXT_PRIVATE_STANDALONE_CONFIG
and __NEXT_PRIVATE_ORIGIN in process.env at runtime. These leak into every
child process spawned by the Electron main process (Claude Code CLI,
node version checks, package installs, etc.), which in turn pollutes
tmux/terminal sessions.

When other Next.js projects detect __NEXT_PRIVATE_STANDALONE_CONFIG in their
environment, they skip normal next.config loading and use CodePilot's baked-in
config instead — silently breaking builds and dev servers system-wide.

Fix: strip all __NEXT_PRIVATE_* variables when constructing env objects for
child processes. The standalone server.js already sets these internally, so
they don't need to be passed from the parent.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-03-05 10:59:39 +08:00
7418andClaude Sonnet 4.6 5413eb55ba refactor: 简化 macOS 构建 — 只签名不公证,禁用原生热更新
CI (.github/workflows/build.yml):
- 删除 mac_notarize 输入、notarization strategy/credentials 步骤
- 双架构回归单步构建,统一 -c.mac.notarize=false
- 证书缺失时硬失败,不 fallback ad-hoc
- 上传产物移除 blockmap / latest-mac.yml
- release 收集资产移除 blockmap / yml 元数据

electron-builder.yml:
- mac.notarize 固定为 false

Electron 主进程 (main.ts):
- 移除 initAutoUpdater / setUpdaterWindow 调用和 import

Preload (preload.ts):
- 移除 updater bridge,不再暴露 electronAPI.updater

Updater (updater.ts):
- 恢复为 no-op stub

前端 AppShell 无需改动 — isNativeUpdater 运行时检测 updater 不存在,
自动走 /api/app/updates 浏览器模式(全量下载链接)。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 13:27:35 +08:00
7418andClaude Sonnet 4.6 db86644c7e feat: macOS 双架构分离构建 — x64 只签名,arm64 签名+条件公证
CI:
- 拆分为 x64 和 arm64 两个独立构建步骤
- x64: 签名但不公证(-c.mac.notarize=false),timeout 15min
- arm64: 签名 + 按版本号条件公证(vX.Y.0 公证,vX.Y.Z 只签名),timeout 35min
- 先跑 x64,stash 产物后跑 arm64,确保 latest-mac.yml 来自 arm64

Electron:
- electron/main.ts: darwin+x64 跳过 initAutoUpdater
- electron/preload.ts: darwin+x64 不暴露 updater bridge
- 前端 AppShell 已有运行时检测(!!window.electronAPI?.updater),
  x64 自动 fallback 到 browser 模式更新检查

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 11:35:50 +08:00
7418andClaude Sonnet 4.6 0e38e4460e feat: macOS Developer ID 签名 + notarization + 原生热更新
签名 & 公证:
- build/entitlements.mac.plist, build/entitlements.mac.inherit.plist — Electron hardened runtime 所需权限(JIT、unsigned memory、disable library validation)
- electron-builder.yml — 启用 hardenedRuntime、entitlements、notarize: true
- scripts/after-sign.js — 环境变量 + codesign -d 双重检测,有 Developer ID 时跳过 ad-hoc;无证书时 fallback ad-hoc
- .github/workflows/build.yml — 映射签名 secrets(MAC_CERT_P12_BASE64 等),验证步骤断言 Developer ID Authority + TeamIdentifier,遍历双架构 .app

原生热更新:
- electron/updater.ts — 从 no-op 重写为完整 electron-updater 实现(autoDownload:false, IPC handlers, 启动 10s 延迟检查)
- electron/preload.ts — 恢复 updater IPC bridge
- src/components/layout/AppShell.tsx — 运行时检测 native updater,useEffect 监听 updater:status 事件,native 优先 + browser fallback

其他:
- README_CN.md — 更新自动更新功能描述
- package.json — 版本号升至 0.23.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 00:46:51 +08:00
7418andClaude Opus 4.6 6ad821d3af feat: 多 IM 远程桥接系统 + Bridge 一级导航 + bug 修复
**Bridge 系统核心(src/lib/bridge/)**
- bridge-manager: 生命周期编排、adapter 事件循环、会话级并发控制
- channel-adapter: 抽象基类 + 注册式 adapter 工厂
- channel-router: IM 地址 → CodePilot session 自动映射
- conversation-engine: 服务端消费 streamClaude() SSE 流
- permission-broker: 权限请求转发到 IM 内联按钮
- delivery-layer: 出站分片、限流、重试退避、HTML 降级
- telegram-adapter: Telegram 长轮询 + offset 安全水位 + 幂等去重
- security/: 路径校验、危险输入检测、滑动窗口限流

**Telegram 通知 Bot(src/lib/telegram-bot.ts)**
- 独立通知模式,与 bridge 模式互斥
- bridgeModeActive 使用 globalThis 存储,避免 HMR 重置导致轮询冲突

**API 路由**
- /api/bridge: GET 状态查询 + POST start/stop/auto-start
- /api/bridge/channels: 活跃通道列表
- /api/bridge/settings: bridge 设置读写
- /api/settings/telegram: 凭据管理(含 allowed_users 白名单)
- /api/settings/telegram/verify: 连接验证 + chat ID 自动检测

**UI 重构:Bridge 提升为一级导航**
- NavRail 新增 Bridge 图标导航项
- /bridge 页面:BridgeLayout hash 路由,Bridge + Telegram 两个子 tab
- BridgeSection: 总开关、状态、启停、通道开关、适配器状态、默认设置
- TelegramBridgeSection: 凭据配置 + 白名单 + Setup Guide(6 步)
- Settings 移除 Telegram 和 Bridge tab,只保留 4 个核心 tab

**Bug 修复**
- bridge-manager: runAdapterLoop 在 state.running=true 之前被调用,
  while 条件同步求值为 false 导致消费者循环不启动。修复为先设 running
  再启动 loop
- telegram-bot: bridgeModeActive 改用 globalThis 防止 HMR 丢失状态
- settings/telegram route: TELEGRAM_KEYS 补充 telegram_bridge_allowed_users

**Electron**
- 窗口关闭时 bridge 活跃则最小化到系统托盘而非退出
- 启动时通过 auto-start API 恢复桥接
- preload 暴露 bridge 相关 IPC

**文档**
- docs/bridge-system.md: 完整架构文档
- docs/chat-sdk-integration-feasibility.md: Chat SDK 集成调研
- CLAUDE.md 添加 bridge 文档链接

chore: bump v0.21.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:18:19 +08:00
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