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>
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>
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>
Image Generation Refactor:
- MessageInput: add onImageGenerate callback, remove skill fetch dependency
- ChatView: implement handleImageGenerate that creates image-gen-request
message for ImageGenConfirmation UI, then user selects params and generates
- New API route POST /api/chat/messages for DB-only message persistence
- image-gen-completed event now only persists notice to DB, no longer triggers model
- Reference images passed via module-level Map (imageGenRefStore) to avoid
DB bloat from base64 data; user message DB content stores metadata only
Bug Fixes:
- Fix useCallback dependency missing imageGen causing stale closure reads
- Fix React Hooks order violation in MessageItem (early return before hooks)
- Fix localStorage cache collision across sessions (key now includes sessionId)
- Fix empty src attribute in FileAttachmentDisplay for DB-restored messages
- Add JSON parse fallback for malformed image-gen-request blocks
Gallery Reference Images:
- /api/media/generate saves reference images to disk, stores paths in metadata
- /api/media/gallery extracts referenceImages from metadata in mapRow
- GalleryDetail displays reference image thumbnails
- ImageGenCard supports referenceImages prop for chat display
UI Changes:
- ImageGenToggle: replace paint brush icon with text label (en: Image, zh: 生图)
- Model selector button: remove provider name display to save space
- ImageGenConfirmation: support referenceImagesData prop for base64 preview
i18n:
- Add imageGen.toggleLabel key (en: Image, zh: 生图)
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>
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)
Deduplicate 150-line inline SSE parsing from ChatView into a reusable
hook. ChatView reduced from 594 to 490 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Click files in the file tree to open a dedicated preview panel with
source/rendered toggle for .md/.mdx/.html/.htm files. Preview panel
supports drag-to-resize (320–800px) with localStorage persistence.
Bump version to 0.9.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add automatic update detection (checks GitHub Releases every 8h with
dialog prompt and blue dot on Settings icon) and a skip-permissions
toggle in Settings that uses the SDK's native bypassPermissions mode
to auto-approve all tool actions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>