Root cause: esbuild 0.27.3 misparses `node-pty` inside JSDoc comments as a
code expression `node - pty` (subtraction). This produces a bare
`ReferenceError: node is not defined` at app.asar/dist-electron/main.js:35
on startup.
Fixes:
- terminal-manager.ts: replace JSDoc block with line comments and remove all
literal `node-pty` strings (reference docs/handover instead)
- build-electron.mjs: clean dist-electron/ before every build to prevent
stale artifact contamination in app.asar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- provider-catalog: getDefaultModelsForProvider() now returns preset's
defaultModels even when empty, instead of falling through to
ANTHROPIC_DEFAULT_MODELS. Fixes Volcengine (defaultModels: []) incorrectly
showing Sonnet/Opus/Haiku.
- providers/models route: remove DEFAULT_MODELS fallback when both DB and
catalog are empty — providers like Volcengine that require user-specified
model names should show only those models.
- Add missing src/app/api/chat/sessions/by-cwd/route.ts that was untracked;
without it worktree switching would 404 in release builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Assistant trigger CAS (P1):
- hook-triggered route: added expectedOwner param for compare-and-swap —
rejects if current owner doesn't match, closing the race where two tabs
both clear then both claim the lock
- useAssistantTrigger: clear sends expectedOwner (stale session), set sends
expectedOwner: null; non-2xx responses now bail instead of falling through
- Server-side completion (chat/route.ts): only clears lock if owner matches
current sessionId, preventing completed sessions from wiping active locks
- Compensation branch: clear now passes expectedOwner to avoid bypassing CAS
Image-gen LIKE escape (P2):
- db.ts: escape backslashes before % and _ since ESCAPE '\' makes \ the
escape char — prevents Windows paths / escaped JSON from corrupting the
LIKE pattern and silently falling back to prompt-prefix matching
Provider options fetch race (P2):
- page.tsx + ChatView.tsx: provider options fetch now uses AbortController
with cleanup on dependency change — prevents stale slow responses from
overwriting the current provider's thinking/context_1m state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New plugin-discovery.ts: scans ~/.claude/plugins/marketplaces/ and
external_plugins/, reads .claude-plugin/plugin.json manifests, merges
enabledPlugins across user/project/local settings layers with write
escalation to local when higher layers override
- Rewrite /api/plugins and /api/plugins/[id] to use real plugin manifests
with name@marketplace composite keys, blocklist, and multi-layer
enable/disable with CAS-style write escalation
- SDK plugin loading delegated to SDK itself (no explicit queryOptions.plugins)
— ensures parity with Claude CLI's settingSources resolution
- Extended init meta forwarding (plugins, mcp_servers, output_style) in
claude-client.ts and useSSEStream.ts
- Per-provider plugin cache in agent-sdk-capabilities.ts with
getCachedPlugins/setCachedPlugins
- Skills route: provider-scoped plugin cache lookup via sessionId param,
external_plugins commands scan, loaded status annotation
- Updated PluginInfo type with marketplace, location, author, capability flags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite install-check-prerequisites with multi-path Claude CLI detection
(native, bun, homebrew, npm) and structured result reporting
- Improve InstallWizard with step-by-step progress and better error handling
- Enhance ConnectionStatus with detailed status display and invalidation
- Add /api/claude-status/invalidate route for cache-busting
- Expand platform.ts with richer detection utilities
- Add onInitMeta handler in stream-session-manager
- Update electron.d.ts types for new IPC channels
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace fixed-timeout stale detection with localStorage heartbeat mechanism
- Heartbeat writes {sid, ts} every 10s; isOwnerAlive checks sid matches AND freshness
- Stop heartbeat when triggered stream completes (useEffect on !isStreaming)
- removeHeartbeatIfOwned: only delete key if it still belongs to this session
(prevents new owner's heartbeat from being wiped by old session's cleanup)
- Export clearOnboardingHeartbeat with optional sessionId parameter
- hook-triggered route sets/clears hookTriggeredAt alongside hookTriggeredSessionId
- MiniMax model auto-correction: reset model when not in current provider's list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Image reference store session-scoped:
- Rewrite image-ref-store.ts: all keys/functions now scoped by sessionId
- Thread sessionId through MessageList → StreamingMessage/MessageItem → ImageGenConfirmation
- ChatView loads last-generated images for current session on mount
Image write-back robustness:
- Remove localStorage caching from ImageGenConfirmation (root cause of stale results)
- Add rawRequestBlock for exact content matching in DB fallback query
- updateMessageBySessionAndHint prefers exact block match, falls back to prompt hint
- PUT route passes raw_request_block to DB function
- Add retry-after-3s when first PUT fails and no messageId available
- Exclude already-completed messages (NOT LIKE image-gen-result) from update query
New session page (/chat) fix:
- Add createdSessionId state, set after session creation, pass to MessageList
- Prevents first-message image-gen-request from inheriting stale panel sessionId
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ProviderOptionsSection component for per-provider thinking_mode and context_1m
- Store options in options_json column (DB providers) or settings table (env provider)
- Add /api/providers/options GET/PUT route
- Fix SDK integration: use `betas` (not `betaHeaders`) for context-1m-2025-08-07
- ChatView and /chat page always reset thinkingMode on provider change (isolation fix)
- Auto-correct model when switching providers if model not in new provider's list
- Add i18n keys for provider options in both en.ts and zh.ts
- Update test fixtures with options_json field
- Remove unused lastAssistantText variable in claude-client.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract 4 self-contained sub-components from MessageInput.tsx:
- SlashCommandPopover (243L): slash command filtering, rendering, selection
- CliToolsPopover (128L): CLI tool selection with search/filter
- ModelSelectorDropdown (150L): provider/model selector dropdown
- EffortSelectorDropdown (75L): thinking effort level selector
All components have clean props interfaces ready for integration.
MessageInput.tsx wiring deferred to follow-up — the file's 1,659 lines
of tightly coupled state make this a careful, incremental process.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge chat/CodeBlock.tsx (Prism via react-syntax-highlighter) into
ai-elements/code-block.tsx (Shiki):
- Port collapse/expand (COLLAPSE_THRESHOLD=20, VISIBLE_LINES=10) from Prism version
- Port InlineCode component export
- Port "Copy as Markdown" functionality
- Update ToolCallBlock.tsx import to use ai-elements/code-block
- Delete src/components/chat/CodeBlock.tsx
Note: react-syntax-highlighter still used by DocPreview and FilePreview,
so dependency not removed yet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New hooks:
- useSettings: generic settings CRUD (fetch/save with loading/saving states)
- useBridgeAdapter: bridge adapter settings + verify flow
- useBridgeStatus: bridge status polling + start/stop control
- useAccountInfo: Claude SDK account info fetching
Refactored components:
- GeneralSection: replace inline fetchAccountInfo with useAccountInfo hook
- BridgeSection: replace inline fetchStatus/startBridge/stopBridge + polling
interval with useBridgeStatus hook (removed ~50 lines)
The remaining bridge adapter sections (Telegram/Discord/Feishu/QQ) can be
migrated to useBridgeAdapter in a follow-up — hooks are ready for adoption.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
- 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>
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>
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>
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>
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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>