Commit Graph
274 Commits
Author SHA1 Message Date
7418andClaude Opus 4.6 6ea323b92f feat: add reusable pattern components (PR2)
Create src/components/patterns/ with 6 pure-presentation components
that abstract repeated layout patterns from settings/bridge pages:

- SettingsCard: rounded card with optional title/description
- FieldRow: label+description left, control right, optional separator
- SectionPage: max-width page container with consistent spacing
- StatusBanner: success/warning/error/info inline status messages
- EmptyState: centered empty state with icon, title, description, action
- IconAction: ghost icon button with optional tooltip wrapper

All components are zero-side-effect, only import from React and @/lib/utils
(plus ui/button and ui/tooltip for IconAction).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:45:32 +08:00
7418andClaude Opus 4.6 2b8c7cba53 chore: establish UI governance infrastructure (PR1)
- Add .editorconfig for consistent formatting (2-space indent, LF, UTF-8)
- Add docs/ui-governance.md defining 4-layer architecture, icon strategy,
  color token rules, component size limits, and new primitive approval flow
- Update eslint.config.mjs with governance rules:
  - warn on native <button/input/select/textarea> in business components
  - warn on lucide-react imports (prefer @phosphor-icons/react)
  - warn on component files exceeding 500 lines
  - error on data logic imports in patterns/ layer
- Update components.json iconLibrary from "hugeicons" to "phosphor"

Note: 4 pre-existing test failures (assistant-workspace, db-shutdown,
provider-resolver, timezone-boundaries) unrelated to this change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:43:40 +08:00
7418andClaude Opus 4.6 45193de8af chore: bump version to 0.32.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:03:31 +08:00
7418andClaude Opus 4.6 16edf9f59c feat: CLI Tools — curated tool catalog, detection, install, chat awareness
New sidebar page for managing system CLI tools (ffmpeg, jq, ripgrep, yt-dlp, pandoc).

Core modules:
- cli-tools-catalog.ts: static catalog of 6 curated tools + EXTRA_WELL_KNOWN_BINS
- cli-tools-detect.ts: system detection via which/where + --version (2min cache)
- cli-tools-context.ts: builds <available_cli_tools> block for chat system prompt

API routes:
- GET /api/cli-tools/catalog, /installed, /[id]/status, /[id]/detail
- POST /api/cli-tools/[id]/install (SSE streaming), /[id]/describe (AI gen)

UI components:
- CliToolsManager: installed + recommended sections with grid layout
- CliToolCard: two variants (installed/recommended) with status badges
- CliToolDetailDialog: intro, use cases, guide steps, example prompts
- CliToolInstallDialog: SSE-based install progress with live terminal log

Chat integration:
- Chat input toolbar: Terminal icon opens CLI tool picker popover
- System prompt injection: buildCliToolsContext() in /api/chat
- MessageInput: CLI popover with search, keyboard nav, locale-aware prefill
- NavRail + ChatListPanel: frosted glass (bg-sidebar/80 backdrop-blur-xl)
- SlashCommandButton: Lightning icon, unified 16px toolbar icons
- input-group: shadow-md → shadow-sm
- Model selector: searchable popover with provider grouping

Docs:
- docs/handover/cli-tools.md + apps/site/content/docs/{en,zh}/cli-tools.mdx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 19:56:29 +08:00
7418andClaude Opus 4.6 4e603323c4 fix: user bubble color not rendering — use Tailwind v4 variable syntax
The bg-[var(--user-bubble)] arbitrary value syntax wasn't working with
Tailwind v4's Lightning CSS pipeline. Switch to bg-(--user-bubble) which
is Tailwind v4's native CSS variable reference syntax.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:49:51 +08:00
7418andClaude Opus 4.6 18a77dc915 fix: file tree attachment on Electron + model selection follows session
File tree "+" button (Bug 1):
- Replace fragile fetch/blob attachment bridge with @filepath text insertion
- Works identically on web and Electron (pure text, no /api/files/raw fetch)
- Remove unused mimeFromFilename helper

Model selection follows session (Bug 2):
- page.tsx: include model/provider_id in session creation request
- [id]/page.tsx: add sessionInfoLoaded gate — ChatView only mounts after
  session metadata is fetched, preventing stale localStorage fallback
- SplitColumn.tsx: same sessionInfoLoaded gate for split-pane mode
- ChatView.tsx: useEffect sync only overrides model/provider when props
  are non-empty; empty = genuinely no model saved (old/imported sessions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:46:34 +08:00
7418andClaude Opus 4.6 e5a48ca6af feat: migrate icon library from Hugeicons to Phosphor + UI polish
Icon library migration:
- Replace @hugeicons/react with @phosphor-icons/react across 60+ components
  (Phosphor supports 6 weight variants: thin/light/regular/bold/fill/duotone)
- Update apps/site (marketing) to use Phosphor icons
- Remove leftover svg.hugeicons CSS rules from globals.css

UI improvements:
- NavRail: selected tab icons use filled weight, unselected use regular
- User chat bubble: dark bg + white text in light mode, light bg + dark text
  in dark mode (new --user-bubble / --user-bubble-foreground CSS variables)
- Fix expand/collapse icons: use CaretRight (triangle) instead of ArrowRight
  in file-tree.tsx and tool-actions-group.tsx

Lint fixes:
- Fix eslint react-hooks/static-components in CodeBlock, ToolCallBlock,
  tool-actions-group — use createElement() instead of PascalCase variable
- Fix react-hooks/rules-of-hooks in MessageItem — move early return after hooks
- Fix react-hooks/set-state-in-effect in GalleryDetail — use ref pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 11:12:12 +08:00
7418andClaude Opus 4.6 5adeb3548e docs: add official documentation links to all READMEs
Link to codepilot.sh docs (en + zh) for Providers, MCP, Skills,
Bridge, Assistant Workspace, Installation, and FAQ.
Updated English, Chinese, and Japanese READMEs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 01:02:51 +08:00
7418andClaude Opus 4.6 5e18acb63d feat: provider auth style selector & edit UX improvements
- Anthropic Third-party API: add API Key / Auth Token selector in connect dialog
  with proper extra_env injection and auth style detection
- Edit mode: reuse PresetConnectDialog for matched providers instead of generic
  ProviderForm, showing only relevant fields consistent with connect experience
- Edit mode: show masked key (dots) instead of empty field; switching auth style
  clears key and requires re-entry; switching back restores masked value
- Edit mode: expose headers_json, env_overrides_json, notes in advanced section
  so all fields remain visible and editable
- Edit mode: role_models_json merge logic preserves unseen roles (reasoning, small)
  while allowing clearing of visible mapping fields
- Dialog: add max-h-[calc(100vh-4rem)] + overflow-y-auto to DialogContent base;
  remove overflow-hidden from preset dialog so scrolling actually works
- Connected provider badge: detect ANTHROPIC_AUTH_TOKEN in extra_env to show
  correct "Auth Token" vs "API Key" label
- i18n: add provider.authToken, provider.authStyle keys (en + zh)
- Bump version to 0.31.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:57:40 +08:00
7418andClaude Opus 4.6 ac6f5f891a fix: remove conflicting bridge.mdx that hid bridge sub-pages in en docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:55:22 +08:00
7418andClaude Opus 4.6 d360b53bde docs: translate full Chinese docs to English — match structure and content
- Rewrite index.mdx as proper getting started guide
- New: chat.mdx (modes, permissions, context management)
- New: skills.mdx (categories, marketplace, local skills)
- New: design-agent.mdx (single/batch image generation)
- New: gallery.mdx (browsing, filtering, detail view)
- Rewrite providers.mdx — CLI env auth, cc switch caveat, API Key vs
  Auth Token, Chinese provider presets, model mapping, priority chain
- Rewrite mcp.mdx — three transport types, dual view modes
- Rewrite assistant-workspace.mdx — align with Settings > Assistant tab
- Rewrite faq.mdx — comprehensive Q&A
- Bridge split into 5 pages: overview + Telegram + Discord + Feishu + QQ
- Flatten single-page folders to remove sidebar expand arrows
- Update meta.json with new pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:48:55 +08:00
7418andClaude Opus 4.6 0197ceec4e docs: 服务商配置补充 API Key / Auth Token 认证类型选择说明
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:45:51 +08:00
7418andClaude Opus 4.6 c67f3ef82b docs: 重写中文文档 — 全量覆盖功能、中文 UI 标签、桥接分页
- 重写 index.mdx 为真正的快速开始指南,链接服务商配置
- 新增 chat.mdx(对话模式、权限、上下文管理)
- 新增 skills.mdx(技能分类、市场、本地管理)
- 新增 design-agent.mdx(单张/批量图片生成、参考图、连续编辑)
- 新增 gallery.mdx(素材库浏览、筛选、详情操作)
- 重写 providers.mdx — CLI 环境认证 vs 手动添加、cc switch 不生效说明、
  国内服务商预设、Anthropic 第三方模型映射、服务商优先级链
- 重写 mcp.mdx — 三种传输类型(stdio/SSE/HTTP)、列表+JSON 双视图
- 重写 assistant-workspace.mdx — 对齐实际设置>助理标签页
- 重写 faq.mdx — 更全面的问答覆盖
- 桥接拆分为 5 页:总览(斜杠命令、全局设置) + Telegram + Discord + 飞书 + QQ
- Discord 开发者模式获取 ID 说明移入配置流程
- 飞书长连接模式启动顺序说明
- 所有 UI 按钮/菜单名称改为中文翻译(设置、服务商、技能、桥接等)
- 扁平化无子页面的 folder/index.mdx → page.mdx,消除侧边栏多余展开三角

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 00:13:16 +08:00
7418andClaude Opus 4.6 9fae911760 fix: dark mode button visibility — RainbowButton and DownloadButton
- RainbowButton: dark mode text white→dark for contrast on white bg
- DownloadButton: dark mode invert to white bg + dark text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 23:21:45 +08:00
7418andClaude Opus 4.6 464ee64a52 fix: download button dark mode — invert colors for visibility
Light: dark bg + white text. Dark: white bg + dark text.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 23:16:51 +08:00
7418andClaude Opus 4.6 386224d7d9 fix: download button use fixed colors for consistent visibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 22:27:55 +08:00
7418andClaude Opus 4.6 6e666b1297 feat: SEO optimization, favicons, and dark mode download button fix
- Add comprehensive metadata: Open Graph, Twitter Card, keywords, robots
- Add per-page metadata with i18n alternates for homepage (en/zh)
- Add robots.ts, sitemap.ts (dynamic from docs), manifest.ts
- Add favicon (icon.png 32px), apple-icon.png (180px), PWA icons (192/512px)
- Add og-image.png (1200x630) for social sharing
- Update site.config.ts with canonical URL and improved description
- Fix DownloadButton dark mode: white-on-white text → dark:bg-white dark:text-black

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 22:03:52 +08:00
7418andClaude Opus 4.6 3f56edc4c8 fix: upgrade next 15.3.3 → 15.3.6 to resolve CVE-2025-66478
Vercel blocks deployment of vulnerable Next.js versions.
15.3.6 is the patched release for the App Router vulnerability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:12:00 +08:00
7418andClaude Opus 4.6 3b87e56134 fix: site build/deploy blockers — local fonts, lint cleanup, Vercel compat
- Replace next/font/google with next/font/local to eliminate build-time
  dependency on fonts.googleapis.com (Inter + Geist self-hosted in repo)
- Centralize font definitions in src/lib/fonts.ts, single entry point
- Remove unused Geist import and AnimatePresence import (lint warnings)
- Delete unused community/download placeholder pages (build errors)
- Add outputFileTracingRoot for monorepo vendor chunk resolution
- Make root prepare script CI-safe (husky graceful fallback)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:59:39 +08:00
7418andClaude Opus 4.6 1359758fbf feat: add marketing site and docs app (apps/site)
- Homepage with hero section (typewriter animation, ChatDemo, FlickeringGrid),
  features section, open-source section (GitHub stars), FAQ accordion, final CTA
- Docs powered by fumadocs-ui with i18n (en/zh), custom top nav bar with
  search, GitHub link, and language switcher
- Marketing content system with typed en/zh content files
- Custom components: RainbowButton, ScrollNav, ChatDemo animation
- Docs pages: Getting Started, Installation, Providers, MCP, Bridge,
  Assistant Workspace, FAQ
- DownloadButton MDX component linking to GitHub Releases
- Monorepo workspace config (apps/*, packages/*)
- Fix FAQ accordion lint (pure CSS grid-template-rows animation, no useEffect)
- Fix RainbowButton empty interface lint error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:25:57 +08:00
7418andClaude Opus 4.6 9b2793c9d3 chore: bump version to 0.30.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:56:55 +08:00
7418andClaude Opus 4.6 281e7f9502 fix: skills/MCP/completion system overhaul — separate skill kinds, fix MCP remote servers, deduplicate completion processing
Skills system:
- Replace `CommandBadge.isSkill: boolean` with `kind: SkillKind` (agent_skill | slash_command | sdk_command | codepilot_command)
- handleSubmit dispatches by kind: agent_skill retains skill name in prompt, slash/sdk commands pass through to SDK, codepilot commands expand via COMMAND_PROMPTS
- Popover groups commands into Commands / Slash Commands / Agent Skills
- API `/api/skills` returns `kind` field; `displayOverride` persisted through full chain (frontend → API → DB)
- Forward SDK `system:init` slash_commands/skills metadata to frontend via SSE

MCP management:
- Fix remote server (SSE/HTTP) creation: validate `url` instead of `command`
- Fix dual-config read/write asymmetry: PUT routes servers by `_source` to correct file (~/.claude.json vs ~/.claude/settings.json)
- DELETE checks both config files; POST checks both for name collision
- McpManager preserves `_source` tags on edit/rename; JSON editor only manages settings.json servers

Completion processing:
- Extract core logic into `onboarding-processor.ts` and `checkin-processor.ts` (shared by route handlers and server-side detection)
- Remove frontend `detectAssistantCompletion` from ChatView — server-side path in `finally` block is now the single source of truth
- Replace hard-coded `fetch("http://localhost:PORT/...")` with direct function imports
- Both processors are internally idempotent (check state before processing)

Other:
- `settingSources` always includes 'user' so SDK loads ~/.claude/skills/
- Add 24 unit tests for SkillKind dispatch logic
- Add onboarding-completion extraction tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 12:49:43 +08:00
7418andClaude Opus 4.6 789b453e92 fix: onboarding stability, invalid JSON from hooks, file tree race conditions
Issue 1 — Onboarding re-triggering after completion:
- ChatView.tsx: fence regex now tolerates CRLF, trailing whitespace, leading
  whitespace before closing fence; JSON.parse input trimmed
- ChatView.tsx: hookTriggeredSessionId only cleared when backend returns ok
- assistant-workspace.ts: saveState uses atomic write (tmp + rename)

Issue 2 — "CLI output was not valid JSON" during document reads:
- claude-client.ts: remove all SDK hooks (Notification + PostToolUse) to
  eliminate hook_callback control_request transport that corrupts stdout
- claude-client.ts: TodoWrite sync moved to message stream — tool_use records
  pending input, tool_result emits task_update only on success
- claude-client.ts: notifications derived from system/task_notification and
  result/is_error messages; Telegram forwarding preserved via notifyGeneric

Issue 3 — File tree not updating on project switch:
- FileTree.tsx: AbortController cancels in-flight requests on directory change;
  abort fires before empty-directory early return to prevent stale overwrites;
  error state distinguishes empty dir from load failure; loading always reset
- page.tsx: clear workingDirectory immediately on session switch
- SplitColumn.tsx: clear workingDirectory when active column has no directory

Tests: 9 new tests for fence parsing, atomic write, corrupted state fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:27:54 +08:00
7418andClaude Opus 4.6 f76e4747cd feat: unified provider resolver with protocol-based dispatch
Extract provider resolution logic into two new modules:
- provider-catalog.ts: vendor presets, default model catalogs, protocol definitions
- provider-resolver.ts: unified resolution for all consumers (Claude SDK, AI SDK, model listing)

DB migration:
- Add protocol, headers_json, env_overrides_json, role_models_json columns to api_providers
- Create provider_models table for per-provider model catalog

Consumer refactoring:
- claude-client.ts: replace inline env-building with toClaudeCodeEnv()
- text-generator.ts: replace inline config with toAiSdkConfig()
- conversation-engine.ts, onboarding, checkin, plan routes: use shared resolveProvider()
- /api/providers/models: read from catalog + provider_models table

UI improvements:
- Merge confusing "Custom API (Anthropic-compatible)" into "Anthropic Third-party API"
- Add 3-field model name mapping (sonnet/opus/haiku) in advanced options
- ProviderForm.tsx: support new fields (protocol, env_overrides, role_models)

Bug fixes:
- Protect auth credentials from being deleted by legacy extra_env empty-string overrides
- Fix env var names: ANTHROPIC_DEFAULT_SONNET → ANTHROPIC_DEFAULT_SONNET_MODEL (SDK convention)

Tests: 229/229 passed. Verified with aiberm (no mapping) and pipellm (with mapping).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:30:35 +08:00
7418andClaude Opus 4.6 4dc787c4a4 chore: bump version to 0.29.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:55:59 +08:00
7418andClaude Opus 4.6 94528edac9 fix: use local timezone for date-based features (check-in, usage stats)
Root cause: `new Date().toISOString().slice(0, 10)` returns UTC date,
causing date-based features to be off by up to ±1 day for non-UTC users.

Check-in / assistant workspace:
- Add `getLocalDateString()` utility, replace all UTC date comparisons
- Schema v2→v3 migration: normalize lastCheckInDate only when it matches
  UTC today (ambiguous window); leave past dates untouched so check-in
  triggers correctly after upgrade
- Runtime compat in `needsDailyCheckIn`: accept UTC today as fallback
  for edge cases the migration cannot catch
- `needsDailyCheckIn(state, now?)` accepts optional time for testability

Usage stats:
- Replace single-offset SQL bucketing (`DATE(datetime(..., '+N minutes'))`)
  with JS-side per-row aggregation using `getLocalDateString(new Date(utc))`
- Date methods account for historical DST offset at each message's timestamp
- `getTokenUsageStats(days, now?)` accepts optional time to pin window start
- Window boundary via `localDayStartAsUTC()` is already DST-aware

Tests (new file: timezone-boundaries.test.ts, 22 tests):
- getLocalDateString at UTC+9/UTC-5/UTC boundaries with fixed timestamps
- needsDailyCheckIn: compat suppression, clearly-past trigger, local match
- v2→v3 migration: targeted normalization, past-date preservation, null safe
- localDayStartAsUTC: UTC+8/UTC-5 midnight boundaries
- Usage stats bucketing: UTC+9 cross-day, summary window, DST spring-forward
- All usage stats tests use pinned `now` — no time-bomb from fixed test data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:55:29 +08:00
7418andClaude Opus 4.6 4da188bfe5 feat: theme family system with 12 color palettes + NavRail redesign
Theme system:
- Two-layer architecture: mode (light/dark/system via next-themes) + theme family (color palette via CSS variables)
- 12 theme families: Default, GitHub, Rosé Pine, Tokyo Night, Everforest, Nord, Kanagawa, Night Owl, Poimandres, Vesper, Horizon, SynthWave '84
- Per-family code block highlighting for Prism, HLJS, and Shiki (no more generic oneLight/oneDark fallback)
- Anti-FOUC: synchronous script in <head> reads localStorage and sets data-theme-family before paint
- Theme JSON files in themes/ directory, auto-discovered by server-side loader
- OKLCH color space for all values; CSS specificity html[data-theme-family] beats :root

UI changes:
- NavRail: moved Settings to bottom (replacing theme toggle), removed light/dark toggle button
- Settings: merged General controls into one card with dividers; Appearance section with live Shiki code preview
- Replaced hardcoded blue-500/blue-600 with primary/primary-foreground across 19 components
- Appearance settings: pill mode selector (light/dark/system), theme family dropdown, live code preview

New files:
- src/lib/theme/{types,loader,render-css,context,code-themes}.ts — core theme infrastructure
- src/components/layout/ThemeFamilyProvider.tsx — client context provider
- src/components/settings/AppearanceSection.tsx — appearance settings UI
- src/hooks/useAppTheme.ts — combined theme hook
- themes/*.json — 12 theme family definitions
- docs/handover/theme-system.md — handover documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:15:01 +08:00
7418andClaude Opus 4.6 7ad66f82c4 fix: correct README factual errors and add user-facing content
P1 fixes:
- Replace "Extensions page" with actual MCP + Skills sidebar pages
- Update signing status: macOS is signed (not notarized), Win/Linux unsigned
- Fix Gatekeeper warning description to match signed-but-unnotarized state

P2 fixes:
- Correct Assistant Workspace file locations: soul.md/user.md/claude.md/memory.md
  are at workspace root, .assistant/ is state-only subdirectory
- Translate "Why CodePilot" section to full Japanese (was English regression)
- Add provider auth path clarification (CLI/env optional vs custom required)
- Add specific page names in First Launch (Settings > Providers, Settings > Assistant, MCP, Skills)

Missing content:
- Add structured Documentation section with user guides and developer docs
- Add FAQ section covering: claude not found, no models after provider config,
  dev vs electron:dev, workspace file locations, Bridge platform tokens
- Sync all additions across EN, CN, JA

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:51:35 +08:00
7418andClaude Opus 4.6 a249fb9c4f docs: rewrite READMEs from dev memo to user-facing landing page
- Replace 17-item flat feature list with "Why CodePilot" benefit paragraphs
- Add Quick Links nav bar, First Launch guide, and 3 grouped capability tables
- Collapse ~120-line installation troubleshooting into <details> blocks
- Remove Tech Stack and Project Structure (already in ARCHITECTURE.md)
- Move WeChat QR from hero to Community section
- Add Documentation section linking to ARCHITECTURE.md and docs/
- README_CN.md: full Chinese translation, identical structure
- README_JA.md: Japanese headings/tables, English kept for narrative sections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:32:42 +08:00
7418andClaude Opus 4.6 1e0958f598 feat: QQ bridge channel + SDK crash resilience fixes
QQ Bridge Adapter (new):
- qq-api.ts: AppAccessToken, WebSocket Gateway, heartbeat, passive reply,
  msg_seq auto-increment — pure QQ protocol layer
- qq-adapter.ts: BaseChannelAdapter impl with WebSocket lifecycle,
  C2C_MESSAGE_CREATE handling, image download (base64), dedup, reconnect
- Settings UI (QqBridgeSection.tsx) + API routes (/api/settings/qq)
- i18n keys for en/zh, PLATFORM_LIMITS qq: 2000

replyToMessageId threading:
- bridge-manager.ts: thread msg.messageId through all deliver/command/
  permission paths — required for QQ passive reply (msg_id mandatory)
- permission-broker.ts: accept and forward replyToMessageId

SDK crash resilience (bug fix):
- bridge-manager.ts: check hasError BEFORE saving sdkSessionId — the SDK
  may emit a session_id before crashing, and saving that broken ID caused
  ALL subsequent messages to fail by repeatedly resuming a corrupted session
- claude-client.ts: always clear sdk_session_id on crash, even for fresh
  sessions (SDK can persist a new ID via status event before dying)
- conversation-engine.ts: attach filePath to file objects after disk write
  so streamClaude() reuses on-disk copies (prevents duplicate writes,
  matches desktop route behavior)

QQ permission handling (P1 fix):
- permission-broker.ts: for channels without inline button support (QQ),
  render text-based /perm allow|deny|allow_session commands instead of
  invisible inlineButtons that would deadlock the stream

QQ passive reply budget (P2 fix):
- bridge-manager.ts: QQ-specific delivery limits chunks to 3 max,
  truncates with notice to avoid exhausting passive reply quota
- delivery-layer.ts: export chunkText for reuse

Error message improvement:
- claude-client.ts: when exit code 1 with image files, hint "Provider may
  not support image/vision input" instead of generic auth/network message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:24:54 +08:00
7418andClaude Opus 4.6 c18776f4ca feat: integrate Claude Agent SDK capabilities — model/command discovery, effort/thinking, MCP runtime, file rewind, structured output
Systematically integrate high-value SDK capabilities while preserving the
multi-provider architecture:

SDK capability discovery (per-provider cache):
- agent-sdk-capabilities.ts: cache models, commands, account info, MCP status
  per provider via Map<providerId, cache> to prevent cross-provider pollution
- claude-client.ts: fire-and-forget captureCapabilities() after query() init
- providers/models: merge SDK models with static defaults
- skills: merge SDK slash commands with filesystem skills

Query options passthrough:
- thinking (adaptive/enabled/disabled), effort (low/medium/high/max),
  outputFormat, agents, enableFileCheckpointing
- /chat page.tsx: first-message path now includes effort/thinking (was missing)
- stream-session-manager: passes effort/thinking in POST body

Graceful interrupt:
- /api/chat/interrupt: conversation.interrupt() before abort fallback
- stream-session-manager: tries interrupt first, aborts after 2s timeout

MCP runtime management:
- /api/plugins/mcp/status: live status from active Query, auto-resolves
  providerId from session DB record (prevents wrong-provider cache writes)
- /api/plugins/mcp/reconnect + toggle: reconnect/enable/disable servers
- McpManager + McpServerList: runtime status indicators with action buttons

File checkpointing & rewind:
- enableFileCheckpointing=true for code mode by default
- rewind_point SSE: only emitted for prompt-level user messages
  (parent_tool_use_id===null) and skips autoTrigger turns
- /api/chat/rewind: dry-run preview + actual rewind via rewindFiles()
- MessageList: RewindButton with dry-run preview

Structured output:
- /api/chat/structured: reads SDKResultSuccess.structured_output as primary
  path, text fallback only when absent

Account info & thinking config:
- /api/sdk/account: cached account info display
- Settings: thinking_mode in ALLOWED_KEYS, thinking mode selector in UI
- Effort selector in MessageInput with lifted state pattern

New files: 11 route handlers + 2 lib modules + 1 test file
Modified files: 18 (types, client, manager, UI components, i18n)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:22:05 +08:00
7418andClaude Opus 4.6 6c02c135fe fix: composer UI polish and permission selector improvements
Slash command:
- Fix first-click bug: set textarea.value and cursor position before
  calling handleInputChange so selectionStart reads correctly
- Move slash button to right of + (attach) button
- Simplify icon from CommandLineIcon to plain "/" text

Composer action bar:
- Move Agent toggle and permission selector to left side (was centered)
- Adjust spacing: reduce input padding, increase bottom margin

Permission selector:
- Add dropdown arrow indicator (ArrowDown01Icon)
- Change full_access color from orange to red (icon + text + background)
- Check res.ok before updating UI state (prevent false success)
- Make sessionId optional to support /chat new session page
- Log warnings on PATCH failure instead of silent catch

New chat page (/chat):
- Add ChatPermissionSelector with local state before session exists
- Pass permission_profile in session creation payload
- Backend createSession() now accepts and writes permission_profile

Context usage indicator:
- Reduce circle size from 22px to 16px
- Change used-portion color to dark gray (zinc-600/400)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 16:03:19 +08:00
7418andClaude Opus 4.6 111fa8c92e feat: refactor composer to two-layer layout, add session permission & context indicator
Composer restructure:
- MessageInput internal footer now only contains: file button, model
  selector, slash command button, and send button
- Removed mode toggle (Code/Plan) from composer area (logic preserved)
- New ChatComposerActionBar below input with three slots: left (Design
  Agent), center (permission selector), right (context indicator)

New components:
- SlashCommandButton: inserts `/` at cursor, reuses existing slash
  command detection and popover logic
- ChatPermissionSelector: session-level permission toggle (default /
  full_access) with danger confirmation dialog
- ContextUsageIndicator: SVG donut chart showing context usage ratio
  with HoverCard displaying model, tokens, cache stats
- ChatComposerActionBar: slot-based container for action bar items

Session permission (permission_profile):
- DB: new column on chat_sessions, default 'default'
- API: PATCH sessions supports updating permission_profile
- Chat API: bypassPermissions = global setting OR session full_access
- PermissionPrompt: auto-approves and hides when full_access
- Claude client: combines global and per-session bypass flags

Bridge integration:
- permission-broker: auto-approves permissions for full_access sessions
  without sending IM notifications
- conversation-engine: passes bypassPermissions to SDK for full_access
- PATCH route: auto-approves pending bridge permissions on switch to
  full_access

Other:
- ImageGenToggle relabeled to "Design Agent" / "设计 Agent"
- New model-context.ts with MODEL_CONTEXT_WINDOWS lookup
- Provider models API returns optional contextWindow field
- New useContextUsage hook for token usage calculation
- i18n: added composer.*, permission.*, context.* keys (en + zh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:55:38 +08:00
7418andClaude Opus 4.6 9695825007 chore: bump version to 0.27.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:24:20 +08:00
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
7418andClaude Opus 4.6 5eedb5bacc fix: resolve 7 bugs — idle output, permission scroll, file selector, drag area, input reset, markdown tables, panel collapse
- ChatView: consume unconsumed stream snapshots on mount so output
  appears after idle without needing a conversation switch
- PermissionPrompt: extract permission UI from StreamingMessage into a
  fixed-position component at the bottom of ChatView, preventing
  permission popups from scrolling off-screen during long responses
- StreamingMessage/MessageList: remove ~409 lines of permission UI code
  now handled by PermissionPrompt
- AssistantWorkspaceSection: fix macOS Electron file selector by using
  the correct IPC API (window.electronAPI.dialog.openFolder)
- AppShell: increase title bar drag region from h-5 to h-10 (#152)
- ChatView: add key={sessionId} on MessageInput to reset input state
  when switching conversations (#176)
- UpdateDialog: add remark-gfm plugin and table component mappings for
  proper GFM markdown rendering in release notes (#117)
- RightPanel: add border and top margin to collapsed panel toggle for
  visibility (#116)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:24:19 +08:00
jasonjaclyn2017 a53c60531f fix: prevent stale SDK session and tool-marker parroting after idle timeout (#184)
fix: prevent stale SDK session and tool-marker parroting after idle timeout
2026-03-07 10:26:05 +08:00
jasonjaclyn2017 03d2636d7f fix: decouple stream listeners from stream entry lifecycle (#183)
fix: decouple stream listeners from stream entry lifecycle
2026-03-07 10:25:59 +08:00
7418andClaude Opus 4.6 94fdd36d27 feat: assistant workspace V2 — indexing, retrieval, security hardening & workspace switching
Assistant Workspace V2:
- Markdown indexing engine (incremental manifest + chunks JSONL)
- Keyword retrieval with CJK bigram support and hotset boosting
- Directory taxonomy inference and evolution suggestions
- Workspace config management (.assistant/config.json)
- Organize API: capture, classify, move, archive, suggest-evolution

Workspace switching:
- Inspect API (GET /api/workspace/inspect) for pre-switch validation
- Two-phase switching with confirmation dialogs (5 workspace statuses)
- Atomic save: init/reset runs before setSetting(), rollback on failure
- Auto-navigate to new/reused session after switch
- Mismatch banner in ChatView (only for former assistant sessions)
- Debounced path validation with visual indicators

Security hardening:
- Completion fence (onboarding-complete/checkin-complete) only processes
  when session.workingDirectory === assistant_workspace_path (frontend)
  AND session.working_directory === workspacePath (backend double-check)
- assertContained() in workspace-organizer: rejects absolute paths, ~/,
  ../ traversal, and symlink escapes for captureNote/moveFile
- organize API validates all path params at entry (validateRelativePath)
- captureDefault sanitized to relative path on onboarding write
- R_OK + W_OK validation on GET settings, session creation, and PUT

Bug fixes:
- hookTriggeredSessionId now read before auto-trigger; allows retry if
  session has no messages (previous trigger failed silently)
- workspace-switched event listener matches oldPath (not just != newPath)
  so normal project chats never show the mismatch banner
- Daily check-in card hidden when onboarding not complete
- Refresh docs now calls generateRootDocs() + generateDirectoryDocs()
- Banner "Open" button reuses latest session (checkin mode) instead of
  always creating new onboarding session

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:37:02 +08:00
7418andClaude Opus 4.6 19aba25c8f feat: assistant workspace — persistent AI personality & memory via Markdown files (#165)
Add "Assistant Workspace" feature that lets users designate a directory
(e.g. Obsidian vault) containing 4 Markdown files (soul.md, user.md,
memory.md, claude.md) to define AI personality, user profile, long-term
memory, and execution rules. These files are automatically injected into
the system prompt for assistant project sessions.

Core library (src/lib/assistant-workspace.ts):
- Workspace validation, initialization with template files
- File loading with 8000-char truncation, XML prompt assembly (40k limit)
- State management via .assistant/state.json
- Directory docs generation (README.ai.md + PATH.ai.md)
- Case-insensitive file name fallback (soul.md → SOUL.md)

System prompt injection (src/app/api/chat/route.ts):
- Scoped to sessions where working_directory === workspace path
- Workspace prompt prepended before session-level system prompt
- Onboarding/check-in instructions injected as <assistant-project-task>
- autoTrigger flag skips user message save and title update

Chat-based onboarding (10 questions) & daily check-in (3 questions):
- AI conducts conversation, outputs structured completion code blocks
- Frontend detects onboarding-complete/checkin-complete blocks
- Backend calls Claude API to generate file content from answers
- Fallback to raw answers if API call fails

Auto-trigger pipeline:
- Mount trigger (500ms delay) + focus fallback in MessageInput
- assistantTriggerFiredRef prevents duplicate triggers per mount
- hookTriggeredSessionId in state.json prevents cross-reload duplicates
- Daily check-in only triggers in the most recent workspace session
- hookTriggeredSessionId cleared via __clear__ sentinel after completion

API endpoints:
- GET/PUT /api/settings/workspace — path CRUD + file status
- POST /api/workspace/session — create (onboarding) or reuse (check-in)
- POST /api/workspace/onboarding — AI-generate soul.md + user.md
- POST /api/workspace/checkin — AI-update memory.md + user.md
- POST /api/workspace/hook-triggered — set/clear trigger guard
- GET /api/workspace/latest-session — latest session lookup
- POST /api/workspace/docs — refresh directory documentation

UI:
- Settings "Assistant" tab with workspace path, file status, controls
- Violet badge on workspace project group in ChatListPanel
- useAssistantWorkspace hook for state queries

Also includes:
- 102 passing tests (16 new regression tests for workspace logic)
- i18n keys for en.ts and zh.ts
- Handover documentation and execution plan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:31:42 +08:00
Wujie Li 3f19290c8d fix: preserve paragraph breaks between text blocks in bridge responses (#144)
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.
2026-03-05 11:00:06 +08:00
jasonjaclyn2017andClaude Opus 4.6 a1bde18cd1 feat: add View Plan modal and feedback textbox to plan approval UI (#164)
* feat: add "View Plan" button with fullscreen modal to ExitPlanMode UI

When Claude writes a plan in plan mode, the plan content is written to a
file on disk but the ExitPlanMode UI only shows Approve/Reject buttons —
the user never sees the actual plan without manually finding the file.

Add a "View Plan" button that opens a fullscreen Dialog modal showing
the plan content rendered as markdown. The plan content is extracted from
the tool uses array (the Write tool's input for the plan file), so no
new API endpoints are needed.

Changes in StreamingMessage.tsx:
- extractPlanContent(): walks toolUses backwards to find the last Write
  to a plans/*.md file and returns its content
- ExitPlanModeUI: accepts toolUses prop, renders "View Plan" button
  (hidden if no plan content found), opens Radix Dialog modal with
  MessageResponse markdown renderer
- Modal is 80vh tall, max-w-4xl, scrollable, with Close button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add "Do this instead" feedback textbox to plan approval UI

When rejecting a plan, users can now type feedback and click "Do this
instead" (or press Enter) to send a custom deny message to the SDK.
This matches the Claude Code CLI behavior where users can provide
alternative instructions when rejecting a plan.

Previously, the deny message was hardcoded to "User denied permission"
— the API already supported custom messages but the client never sent
them.

Changes:
- StreamingMessage.tsx: add feedback textbox + "Do this instead" button
  to ExitPlanModeUI, wire onDenyWithMessage callback
- ChatView.tsx: pass denyMessage through handlePermissionResponse
- MessageList.tsx: update onPermissionResponse type signature
- stream-session-manager.ts: add denyMessage param to
  respondToPermission(), use it in the deny decision body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: fetch plan content from disk so View Plan always shows latest version

Previously extractPlanContent read the Write tool's input.content, which
showed stale content when Claude later edited the plan via the Edit tool.

Now extractPlanFilePath finds the plan file path (matching both Write and
Edit tools, with Windows backslash support), and the View Plan button
fetches the file from disk on each click via /api/files/preview.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:00:02 +08:00
jasonjaclyn2017andClaude Opus 4.6 a906172807 fix: handle SDK keep_alive messages to prevent idle timeout during long operations (#163)
The stream idle timer (330s) fires during long-running Claude Code tool
executions because the SDK's keep_alive heartbeat messages are silently
dropped. This causes a false "Stream idle timeout" error even though
Claude is still actively working.

Root cause: claude-client.ts only handles 6 SDK message types in its
switch statement and has no default case, so keep_alive messages from
the SDK are never forwarded to the frontend. The idle timer in
stream-session-manager.ts never gets reset by markActive().

Fix: thread keep_alive through the existing 3-layer event pipeline:
- claude-client.ts: forward keep_alive as SSE event (via default case)
- useSSEStream.ts: add onKeepAlive callback to SSECallbacks interface
- stream-session-manager.ts: call markActive() on keep_alive to reset
  the idle timer

No visible UI change — keep_alive only resets the timer silently.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:59:43 +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 Opus 4.6 113e15e2f4 feat: Discord bridge adapter — 完整实现 Discord 作为第三个桥接渠道
新增文件:
- discord-adapter.ts: 基于 discord.js v14 的适配器,支持 DM/频道消息、
  按钮交互、流式预览(edit-based)、@提及过滤(兼容角色 mention)、
  图片附件下载、!→/ 命令归一化、消息去重、typing indicator
- markdown/discord.ts: Discord 2000 字符分段,代码块围栏自动平衡
- API routes: settings CRUD(Token 掩码)+ verify(Discord REST 验证)
- DiscordBridgeSection.tsx: 设置 UI(凭据、授权、服务器策略、配置指南含 ID 获取方法)
- discord-bridge.test.ts: 22 项单元测试(chunking/auth/command/HTML 转换)

修改文件:
- bridge-manager.ts: Discord 分段投递 + channel-aware stream config
  (Discord 默认 1500ms/40chars/1900max vs Telegram 700ms/20/3900)
- BridgeLayout/BridgeSection: Discord 渠道开关和侧栏入口
- bridge/settings/route.ts: 新增 14 个 Discord 设置键
- next.config.ts: serverExternalPackages 添加 discord.js/zlib-sync
- i18n: 中英文完整翻译(30+ keys)
- docs/handover/bridge-system.md: Discord 架构文档

依赖:discord.js ^14.18.0, zlib-sync ^0.1.9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:32:46 +08:00
7418andClaude Opus 4.6 538cc1b7fd docs: 工程质量保障体系执行计划文档
- 新建 completed/engineering-quality-assurance.md:记录 Harness Engineering
  全部 5 个已完成 Phase 和 4 个未实现 Phase 的详细内容
- 更新 exec-plans/README.md 索引

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:08:49 +08:00
7418andClaude Opus 4.6 935e3d030c fix: i18n 品牌名修正 — Claude → CodePilot
- en.ts / zh.ts: messageList.claudeChat 和 emptyDescription 中的
  "Claude" 改为 "CodePilot",与应用品牌一致

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:00:52 +08:00
7418andClaude Opus 4.6 a8e1bca9d3 chore: bump version to v0.25.1
工程化改进版本:
- 激活验证闭环(pre-commit hook + CI gate + npm test scripts)
- CLAUDE.md 改造 + ARCHITECTURE.md 架构导航
- 执行计划体系 + 技术债务追踪
- chrome-devtools MCP 集成 + UI 验证规则

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:54:53 +08:00
7418andClaude Opus 4.6 a7104aa4eb chore: 集成 chrome-devtools MCP + UI 验证规则
.mcp.json(新建):
- 添加 chrome-devtools MCP server(stdio 模式,npx chrome-devtools-mcp@latest)
- 签入仓库使团队成员 clone 后自动启用

CLAUDE.md:
- 新增"UI 改动必须用 CDP 验证"规则:
  修改组件/样式/布局后,通过 chrome-devtools MCP 截图确认渲染正确、
  检查 console 无报错、模拟交互验证、响应式布局用 device emulation 验证

目的:建立 UI 改动的自动化视觉验证闭环,
AI 修改前端代码后自动启动浏览器截图检查,而非仅靠 typecheck 判断正确性。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:50:18 +08:00
7418andClaude Opus 4.6 62dbecd5dc docs: 执行计划体系 + 技术债务追踪 + CLAUDE.md 执行计划规则
docs/exec-plans/(新建目录):
- README.md — 执行计划规范、模板、何时需要写执行计划
- active/context-storage-migration.md — 从 research/ 迁移,标注 Phase 0-3 进度状态
  (Phase 0 部分完成:sdk_cwd 上线;projects 表和 canUpdateSdkCwd 未实现)
- tech-debt-tracker.md — 4 项已知技术债务(ESLint 存量 error、内存态注册表、
  固定 50 条 fallback、Phase 0 剩余项)

CLAUDE.md:
- 新增"执行计划"区块:中大型功能必须先写执行计划再开工
- 文档区块增加 exec-plans/ 索引

ARCHITECTURE.md:
- 关键文档索引增加执行计划和技术债务条目

docs/research/README.md:
- context-storage-migration-plan 条目增加交叉引用指向执行文档

docs/CLAUDE.md:
- 增加 exec-plans/ 目录说明和文档分类规则

目的:确保 AI 后续会话能自动遵循执行计划流程,
读取进度状态而不需要重新口头解释历史。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:44:12 +08:00