Commit Graph
17 Commits
Author SHA1 Message Date
Nguyễn Ngô Thượng d68bec491c fix(chat): improve error message display with better styling and word-break (#767)
- Add error icon and colored background/border for error messages
- Add break-all and max-w-full to prevent long error text overflow
- CSS: word-break and overflow-wrap for inline code in error messages
2026-04-01 18:36:47 +03:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 6180f388e8 feat(json): add interactive JSON tree viewer with collapse/expand and rainbow colors (#786)
- Add JsonTreeViewer component with collapse/expand for nested objects and arrays
- Add rainbow colors by depth level using CSS color-mix() with syntax theme tokens
- Add virtualization support (@tanstack/react-virtual) for large JSON files (>200 nodes)
- Add JsonTreeView wrapper with Expand All / Collapse All toolbar
- Integrate into FilesView: tree/text toggle button, JSON file detection
- Integrate into ToolPart: auto-detect JSON tool outputs, render as tree
- Integrate into ToolOutputDialog: JSON tree view in expanded dialog
- Add jsonTreeUtils.ts: parse, flatten, path utilities

No new dependencies - uses existing @tanstack/react-virtual.
Colors derived from existing syntax.* theme tokens - works across all themes.

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-04-01 17:30:28 +03:00
Nguyễn Ngô Thượng 744b29c492 feat(files): add HTML preview support in file viewer (#772)
- Add isHtmlFile() helper to detect .html/.htm files
- Add htmlViewMode state for preview/edit toggle
- Add localStorage persistence for HTML view mode preference
- Show PreviewToggleButton for HTML files
- Render HTML in sandboxed iframe with srcdoc
- Inject base tag for relative CSS/JS/image paths to work
- Sandbox permissions: allow-scripts, same-origin, forms
- Reset view mode when switching files
2026-04-01 15:33:17 +03:00
Nguyễn Ngô Thượng b4949c6e33 fix(files): incremental directory refresh on create/rename/delete (#721)
Replace the full-tree nuke-and-reload in refreshRoot() with a targeted
refreshDirectory(parentPath) that only evicts and reloads the single
parent directory whose contents changed.

Before: every create/rename/delete call cleared the entire childrenByDir
cache and reloaded only the root, causing all expanded subdirectories to
flash empty and visually reset.

After: only the parent directory of the affected entry is reloaded in-place;
every other expanded directory keeps its cached children, so the tree state
is preserved and there is no visible flash or scroll-position reset.

Applies to both FilesView and SidebarFilesTree.
2026-03-20 18:25:58 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 60a4110d7f fix(sidebar): show sessions in both Recent and Project sections (#715)
* fix(sidebar): show sessions in both Recent and Project sections

Previously, sessions displayed in the Recent section were filtered out of
their Project section (dedup logic). This meant users could only see a
session in one place, making it hard to find sessions within their project
context.

Now sessions appear in both:
- Recent section: with project name tag for quick identification
- Project section: in their normal grouped position

The project tag (secondaryMeta.projectLabel) was already implemented in
SessionNodeItem but never visible because the dedup logic removed sessions
from project sections before metadata could be populated.

Co-investigated-by: @huylamnguyen

* feat(sidebar): add collapse/expand all projects toggle

When many projects are open, collapsing them one by one is tedious. Add
'Collapse all' and 'Expand all' options to the sidebar display mode dropdown
menu (gear icon).

- Add collapseAllProjects/expandAllProjects callbacks in SessionSidebar
- Pass to SidebarHeader and render in the existing dropdown menu
- Persist collapsed state to localStorage and server settings
- Uses RiContractUpDownLine/RiExpandUpDownLine icons from Remixicon

Co-investigated-by: @huylamnguyen

* refactor: simplify session sidebar section rendering

Remove redundant filtered section aliases in SessionSidebar
Pass project and render sections directly for clearer code

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-03-20 12:35:06 +02:00
Nguyễn Ngô Thượng e57f17996f feat: auto-save file editor with 1.5s debounce (#649)
* fix: project label text hidden by selection overlay in dark mode

In NavRail's ProjectTile, the expanded active item renders an absolutely
positioned background overlay (--interactive-selection) that visually
covers the text label. The label span was missing 'relative z-10',
unlike NavRailActionButton which correctly uses it.

Fixes text being invisible on selected project in dark themes
(nord-dark, dracula-dark, monokai-dark, gruvbox-dark, etc.)

* feat: auto-save file editor with 1.5s debounce

Add debounced auto-save to the file editor so users no longer need to
manually save with Cmd/Ctrl+S or the save button. Files are automatically
saved 1.5 seconds after the user stops typing.

- Debounced auto-save effect that triggers on draft content changes
- Cmd/Ctrl+S still works for immediate save (cancels pending debounce)
- Updated save button UI with contextual status indicators:
  'Saving...' spinner, 'Saved' checkmark, or save icon when dirty
- Reset auto-save status when switching between files
- Applied consistently to both normal and fullscreen editor views
2026-03-14 00:46:43 +02:00
Nguyễn Ngô Thượng d88c782541 fix: project label text hidden by selection overlay in dark mode (#648)
In NavRail's ProjectTile, the expanded active item renders an absolutely
positioned background overlay (--interactive-selection) that visually
covers the text label. The label span was missing 'relative z-10',
unlike NavRailActionButton which correctly uses it.

Fixes text being invisible on selected project in dark themes
(nord-dark, dracula-dark, monokai-dark, gruvbox-dark, etc.)
2026-03-14 00:16:25 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 9a2af4c4d9 feat(nav-rail): add expand/collapse toggle with project names and settings control (#511)
* feat(nav-rail): add expand/collapse toggle with project names and settings control

The NavRail introduced in v1.7.5 only shows project icons without names,
making it difficult to identify which project is active when multiple
projects share similar icons or use letter avatars.

Changes:
- Add expandable NavRail that shows full project names alongside icons
- Default to expanded when multiple projects are open
- Auto-collapse to icon-only mode with a single project (nothing to differentiate)
- Add toggle button at bottom of rail with Cmd+Shift+E keyboard shortcut
- Highlight active project with interactive.selection background for clarity
- Show keyboard shortcut hints in tooltip and expanded label
- Add 'Expand project rail' checkbox in Settings > Appearance > Navigation
- Persist expansion state across sessions

Fixes: NavRail project icons are ambiguous without visible project names

* feat: improve nav rail toggle and navigation settings

- Make nav rail collapsed by default with smoother text fade behavior
- Move nav rail and terminal quick keys controls into a dedicated Navigation section
- Update keyboard shortcuts for logs/status and nav rail expand/collapse

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-26 00:11:08 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 5ab9b1a96e perf(streaming): buffer SSE parts via rAF to coalesce re-renders (#487)
* perf(streaming): buffer SSE parts via rAF to coalesce re-renders

addStreamingPart previously called _addStreamingPartImmediate directly
for every SSE token (~50-100/sec during streaming), causing one Zustand
set() and potential re-render per token.

Now incoming parts are buffered in a module-level queue and flushed once
per animation frame. React 18's automatic batching coalesces the
synchronous set() calls within the rAF callback into a single paint.

Also handles edge cases:
- completeStreamingMessage flushes pending queue before completing
- abortCurrentOperation discards queued parts for the aborted session
- cancelAnimationFrame prevents stale flushes on abort/complete

* perf(streaming): add timeout-backed flush for rAF queue batching

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-24 12:07:05 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn b2101acfbf feat(settings): group agents and skills sidebar by subfolder (#464)
* feat(settings): group agents and skills by subfolder in sidebar

- Server: fix getUserAgentPath() to walk subfolders so grouped agent
  layouts (e.g. agents/business/ceo.md) are correctly resolved
- Store: add 'group' field to AgentWithExtras and DiscoveredSkill,
  parsed from file path at load time
- UI: add collapsible SidebarGroup component with localStorage-persisted
  expand/collapse state
- AgentsSidebar: render custom agents grouped by subfolder name
- SkillsSidebar: render project/user skills grouped by domain folder
- Ungrouped items (flat root) fall through and render normally

* fix(settings): normalize group paths and add agent lookup caching parity

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-23 12:28:24 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 3cd6d051cb perf: fix streaming lag, memory leaks, stuck spinners, and proxy timeout (#483)
* perf: fix streaming lag, memory leaks, and proxy timeout

- PERF-001: Batch all streaming parts via requestAnimationFrame instead of
  per-token Zustand set() calls (~100/sec → 1 per frame)
- PERF-002: Fix direct state.sessionMemoryState mutation inside set() callback
- PERF-003: Debounce messageStore→sessionStore subscription via rAF + 500ms
  title computation delay
- PERF-004: Stabilize SSE callbacks with refs to prevent reconnection storms;
  add 5-min stuck session idle timeout
- PERF-005: Bound messageCache (500 max, LRU eviction), cap registry Maps,
  cleanup on session eviction
- PERF-006: Replace toast duration: Infinity with 30s + id-based dedup
- Fix proxy timeout: POST /session/:id/message 45s → 4min (matches CLI)
- Add vitest + jsdom test infrastructure (61 tests across 7 files)

Addresses: #476 (stuck spinner), #358 (34GB memory leak), #190 (browser lag)

* perf: virtualize tool output rendering (read, edit, write)

- PERF-007: Replace per-line <SyntaxHighlighter> with VirtualizedCodeBlock:
  - ONE Prism.highlight() call for entire file instead of N per-line calls
  - @tanstack/react-virtual renders only visible rows (~30 vs 2000+)
  - Applied to: ToolPart (read, DiffPreview, WriteInputPreview) and
    ToolOutputDialog (unified diff, read content)
- PERF-008: Memoize parseReadToolOutput/parseDiffToUnified via useMemo
  to prevent re-parsing on every re-render

A 2000-line file read now mounts ~30 DOM nodes instead of 2000
SyntaxHighlighter instances, eliminating the main-thread blocking
that caused UI freezes during file operations.

* fix: resolve lint errors (unused vars in tests and VirtualizedCodeBlock)

* chore: trim PR scope to core perf fixes

* fix: restore tool-card highlight stability

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-23 12:05:53 +02:00
Nguyễn Ngô Thượng 989593ed72 feat(files): add 'Reveal in Finder' to file tree context menus (#482)
* feat(session-folders): drag-to-folder DnD, sort by activity, and UX improvements

- Add DraggableSessionRow wrapping each session row so the whole row is
  draggable; stopPropagation prevents outer group-reorder DnD from firing
- Add DroppableFolderWrapper + SessionFolderDndScope (inner DndContext
  scoped per group) with closestCenter collision detection
- DragOverlay matches exact width/height of dragged row so cursor stays
  aligned
- Folder header highlights (ring + primary colour) when a session hovers
  over it during drag
- + button on folder header opens a dropdown: 'New session' / 'New folder'
- + button on each folder row creates a session scoped to that folder
- Empty folders are no longer auto-deleted (removed .filter(sessionIds.length>0)
  from addSessionToFolder / removeSessionFromFolder / cleanupSessions)
- Sessions inside a folder are sorted by most-recent activity (same
  compareSessionsByPinnedAndTime logic used everywhere else)
- Sort comparator now takes sessionAttentionStates so lastUserMessageAt /
  lastStatusChangeAt is used when newer than session.time.updated; all
  sort call-sites and their useMemo/useCallback deps updated accordingly
- Remove foldersMap from cleanup effect deps to prevent cascade re-renders
  when folders change; read current value via getState() instead

* fix(session-folders): new session is placed into the correct folder

sendMessage() was calling useSessionManagementStore.createSession()
directly, bypassing the targetFolderId logic in useSessionStore.createSession.

Fix: read targetFolderId from draft at the top of the draft branch in
sendMessage, then call addSessionToFolder immediately after the session
is created and before the draft is closed. Also propagate targetFolderId
through openNewSessionDraft options and NewSessionDraftState type.

* feat(session-folders): add sub-folder support (one level deep)

- SessionFolder gains optional parentId field for hierarchy
- createFolder accepts parentId to create sub-folders
- deleteFolder cascades to remove all child sub-folders
- SessionFolderItem renders sub-folders before sessions in body;
  new sub-folder button (RiFolderAddLine) visible at depth 0 only
- renderOneFolderItem in SessionSidebar builds the tree recursively;
  sub-folders are indented via depth prop (ml-3 on root's children)
- Persist/hydrate parentId correctly from localStorage

* feat(session): add delete confirm dialogs and improve subtitle UX

- Add confirmation dialogs before deleting sessions or folders
- Show relative time (e.g., '2h ago', '35min ago') for recent sessions
- Replace +/- diff numbers with file change count (e.g., '3 files changed')
- New folders use default name without forcing rename
- Cleaner, less cluttered session list UI

* fix(session-folders): skip folder cleanup while sessions are loading

Prevents race condition on reload where cleanupSessions() runs before
the server returns the full session list, causing folder-session
assignments to be incorrectly wiped from localStorage.

* feat(files): add 'Reveal in Finder' to file tree context menus

Add a new context menu action to reveal files and folders in the system
file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux).

- Add POST /api/fs/reveal server endpoint with cross-platform support
- Add revealPath() to FilesAPI interface and web implementation
- Add 'Reveal in Finder' menu item to SidebarFilesTree and FilesView
- Files are highlighted in Finder (open -R), folders are opened directly
2026-02-23 00:07:22 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 74fa09225a feat(chat): per-session draft persistence + expandable input focus mode (#480)
* feat(session-folders): drag-to-folder DnD, sort by activity, and UX improvements

- Add DraggableSessionRow wrapping each session row so the whole row is
  draggable; stopPropagation prevents outer group-reorder DnD from firing
- Add DroppableFolderWrapper + SessionFolderDndScope (inner DndContext
  scoped per group) with closestCenter collision detection
- DragOverlay matches exact width/height of dragged row so cursor stays
  aligned
- Folder header highlights (ring + primary colour) when a session hovers
  over it during drag
- + button on folder header opens a dropdown: 'New session' / 'New folder'
- + button on each folder row creates a session scoped to that folder
- Empty folders are no longer auto-deleted (removed .filter(sessionIds.length>0)
  from addSessionToFolder / removeSessionFromFolder / cleanupSessions)
- Sessions inside a folder are sorted by most-recent activity (same
  compareSessionsByPinnedAndTime logic used everywhere else)
- Sort comparator now takes sessionAttentionStates so lastUserMessageAt /
  lastStatusChangeAt is used when newer than session.time.updated; all
  sort call-sites and their useMemo/useCallback deps updated accordingly
- Remove foldersMap from cleanup effect deps to prevent cascade re-renders
  when folders change; read current value via getState() instead

* fix(session-folders): new session is placed into the correct folder

sendMessage() was calling useSessionManagementStore.createSession()
directly, bypassing the targetFolderId logic in useSessionStore.createSession.

Fix: read targetFolderId from draft at the top of the draft branch in
sendMessage, then call addSessionToFolder immediately after the session
is created and before the draft is closed. Also propagate targetFolderId
through openNewSessionDraft options and NewSessionDraftState type.

* feat(session-folders): add sub-folder support (one level deep)

- SessionFolder gains optional parentId field for hierarchy
- createFolder accepts parentId to create sub-folders
- deleteFolder cascades to remove all child sub-folders
- SessionFolderItem renders sub-folders before sessions in body;
  new sub-folder button (RiFolderAddLine) visible at depth 0 only
- renderOneFolderItem in SessionSidebar builds the tree recursively;
  sub-folders are indented via depth prop (ml-3 on root's children)
- Persist/hydrate parentId correctly from localStorage

* feat(session): add delete confirm dialogs and improve subtitle UX

- Add confirmation dialogs before deleting sessions or folders
- Show relative time (e.g., '2h ago', '35min ago') for recent sessions
- Replace +/- diff numbers with file change count (e.g., '3 files changed')
- New folders use default name without forcing rename
- Cleaner, less cluttered session list UI

* fix(session-folders): skip folder cleanup while sessions are loading

Prevents race condition on reload where cleanupSessions() runs before
the server returns the full session list, causing folder-session
assignments to be incorrectly wiped from localStorage.

* feat(chat): per-session draft persistence and expandable input focus mode

- Feature 1 (#478): preserve chat draft per session when switching projects
  - Replace global localStorage key with per-session key (draft_${sessionId})
  - Save draft for old session on switch, restore draft for new session
  - Clear draft on submit

- Feature 2 (#479): expandable chat input focus mode (⌘⇧E / Ctrl+Shift+E)
  - Add isExpandedInput state to useUIStore
  - Register expand_input shortcut (mod+shift+e, customizable)
  - Wire shortcut in useKeyboardShortcuts
  - Overlay portal with full-height textarea, Esc to close, auto-close on submit
  - Expand button with tooltip showing keyboard shortcut hint

* fix(chat): switch to in-place desktop focus mode, caret-anchored autocomplete, and no-focus-jump toggle

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-23 00:04:25 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn d0e4dc2704 feat(mcp): add MCP Config Manager UI (#473)
* feat(session-folders): drag-to-folder DnD, sort by activity, and UX improvements

- Add DraggableSessionRow wrapping each session row so the whole row is
  draggable; stopPropagation prevents outer group-reorder DnD from firing
- Add DroppableFolderWrapper + SessionFolderDndScope (inner DndContext
  scoped per group) with closestCenter collision detection
- DragOverlay matches exact width/height of dragged row so cursor stays
  aligned
- Folder header highlights (ring + primary colour) when a session hovers
  over it during drag
- + button on folder header opens a dropdown: 'New session' / 'New folder'
- + button on each folder row creates a session scoped to that folder
- Empty folders are no longer auto-deleted (removed .filter(sessionIds.length>0)
  from addSessionToFolder / removeSessionFromFolder / cleanupSessions)
- Sessions inside a folder are sorted by most-recent activity (same
  compareSessionsByPinnedAndTime logic used everywhere else)
- Sort comparator now takes sessionAttentionStates so lastUserMessageAt /
  lastStatusChangeAt is used when newer than session.time.updated; all
  sort call-sites and their useMemo/useCallback deps updated accordingly
- Remove foldersMap from cleanup effect deps to prevent cascade re-renders
  when folders change; read current value via getState() instead

* fix(session-folders): new session is placed into the correct folder

sendMessage() was calling useSessionManagementStore.createSession()
directly, bypassing the targetFolderId logic in useSessionStore.createSession.

Fix: read targetFolderId from draft at the top of the draft branch in
sendMessage, then call addSessionToFolder immediately after the session
is created and before the draft is closed. Also propagate targetFolderId
through openNewSessionDraft options and NewSessionDraftState type.

* feat(session-folders): add sub-folder support (one level deep)

- SessionFolder gains optional parentId field for hierarchy
- createFolder accepts parentId to create sub-folders
- deleteFolder cascades to remove all child sub-folders
- SessionFolderItem renders sub-folders before sessions in body;
  new sub-folder button (RiFolderAddLine) visible at depth 0 only
- renderOneFolderItem in SessionSidebar builds the tree recursively;
  sub-folders are indented via depth prop (ml-3 on root's children)
- Persist/hydrate parentId correctly from localStorage

* feat(session): add delete confirm dialogs and improve subtitle UX

- Add confirmation dialogs before deleting sessions or folders
- Show relative time (e.g., '2h ago', '35min ago') for recent sessions
- Replace +/- diff numbers with file change count (e.g., '3 files changed')
- New folders use default name without forcing rename
- Cleaner, less cluttered session list UI

* fix(session-folders): skip folder cleanup while sessions are loading

Prevents race condition on reload where cleanupSessions() runs before
the server returns the full session list, causing folder-session
assignments to be incorrectly wiped from localStorage.

* feat(mcp): add MCP Config Manager UI

- Backend: CRUD lib (mcp.js) + 5 REST routes (GET/POST/PATCH/DELETE /api/config/mcp/:name)
- Frontend: Zustand store (useMcpConfigStore), McpSidebar with status dots, McpPage with redesigned UX
  - Textarea command editor: paste full shell commands, auto-split into args, one-arg-per-line view
  - Compact env editor: wide value column, show/hide toggle, paste .env format support
  - Header card: name, type badge, enabled toggle, connect/disconnect button
- Navigation: 'mcp' added to sidebar sections in SettingsView
- TypeScript: all packages pass type-check clean

* fix(mcp): remove constant truthiness lint error in McpPage

Replace '(isNewServer || true) &&' with unconditional render — type
selector should always be visible so the user can switch between
stdio and remote without recreating the server.

* fix: add MCP server management to VS Code backend

- Implement CRUD operations for MCP servers via bridge API
- Support local and remote MCP server configurations with validation
- Add VS Code webview endpoints for MCP server management

* feat: add project-level MCP server configuration

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-22 23:22:33 +02:00
Nguyễn Ngô Thượng 5fc4feee42 feat(session-folders): folder organization, sub-folders, delete confirmations, and UX improvements (#469)
* feat(session-folders): drag-to-folder DnD, sort by activity, and UX improvements

- Add DraggableSessionRow wrapping each session row so the whole row is
  draggable; stopPropagation prevents outer group-reorder DnD from firing
- Add DroppableFolderWrapper + SessionFolderDndScope (inner DndContext
  scoped per group) with closestCenter collision detection
- DragOverlay matches exact width/height of dragged row so cursor stays
  aligned
- Folder header highlights (ring + primary colour) when a session hovers
  over it during drag
- + button on folder header opens a dropdown: 'New session' / 'New folder'
- + button on each folder row creates a session scoped to that folder
- Empty folders are no longer auto-deleted (removed .filter(sessionIds.length>0)
  from addSessionToFolder / removeSessionFromFolder / cleanupSessions)
- Sessions inside a folder are sorted by most-recent activity (same
  compareSessionsByPinnedAndTime logic used everywhere else)
- Sort comparator now takes sessionAttentionStates so lastUserMessageAt /
  lastStatusChangeAt is used when newer than session.time.updated; all
  sort call-sites and their useMemo/useCallback deps updated accordingly
- Remove foldersMap from cleanup effect deps to prevent cascade re-renders
  when folders change; read current value via getState() instead

* fix(session-folders): new session is placed into the correct folder

sendMessage() was calling useSessionManagementStore.createSession()
directly, bypassing the targetFolderId logic in useSessionStore.createSession.

Fix: read targetFolderId from draft at the top of the draft branch in
sendMessage, then call addSessionToFolder immediately after the session
is created and before the draft is closed. Also propagate targetFolderId
through openNewSessionDraft options and NewSessionDraftState type.

* feat(session-folders): add sub-folder support (one level deep)

- SessionFolder gains optional parentId field for hierarchy
- createFolder accepts parentId to create sub-folders
- deleteFolder cascades to remove all child sub-folders
- SessionFolderItem renders sub-folders before sessions in body;
  new sub-folder button (RiFolderAddLine) visible at depth 0 only
- renderOneFolderItem in SessionSidebar builds the tree recursively;
  sub-folders are indented via depth prop (ml-3 on root's children)
- Persist/hydrate parentId correctly from localStorage

* feat(session): add delete confirm dialogs and improve subtitle UX

- Add confirmation dialogs before deleting sessions or folders
- Show relative time (e.g., '2h ago', '35min ago') for recent sessions
- Replace +/- diff numbers with file change count (e.g., '3 files changed')
- New folders use default name without forcing rename
- Cleaner, less cluttered session list UI

* fix(session-folders): skip folder cleanup while sessions are loading

Prevents race condition on reload where cleanupSessions() runs before
the server returns the full session list, causing folder-session
assignments to be incorrectly wiped from localStorage.
2026-02-22 22:56:38 +02:00
Nguyễn Ngô ThượngandBohdan Triapitsyn 6e63f23bb8 feat(sessions): add custom folder grouping for sessions (#460)
* feat(sessions): add custom folder grouping for sessions

Allow users to create custom folders to organize chat sessions.
Folders are stored in localStorage, scoped per project.

Features:
- Create/rename/delete folders from sidebar header
- Move sessions to folders via context menu
- Remove sessions from folders
- Collapse/expand folder state persisted
- Automatic cleanup when sessions are deleted

Implementation:
- useSessionFoldersStore: Zustand store with CRUD + localStorage persistence
- SessionFolderItem: Component for folder header (name, count, actions) + body
- SessionSidebar: Integration with context menu, folder rendering in session list

* fix(sessions): remove sidebar header folder action

* fix: remove folder when they becomes empty

* refactor(sessions): switch folder scope to session directory and clean folder interactions

* fix: move folder actions outside rename mode

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-02-21 01:09:55 +02:00
Nguyễn Ngô Thượng 62e5c3edfe fix(notifications): improve agent progress notifications and permission handling (#459)
* fix(notifications): dismiss cross-window permissions, retry countdown, subtask filter
2026-02-21 00:46:15 +02:00