diff --git a/apps/desktop/src/app/chat/hooks/use-composer-actions.ts b/apps/desktop/src/app/chat/hooks/use-composer-actions.ts
index ecc13808413..a8afdd12830 100644
--- a/apps/desktop/src/app/chat/hooks/use-composer-actions.ts
+++ b/apps/desktop/src/app/chat/hooks/use-composer-actions.ts
@@ -5,6 +5,7 @@ import { droppedFileInlineRef } from '@/app/chat/composer/inline-refs'
import { formatRefValue } from '@/components/assistant-ui/directive-text'
import { useI18n } from '@/i18n'
import { attachmentId, contextPath, pathLabel } from '@/lib/chat-runtime'
+import { readDesktopFileDataUrl, selectDesktopPaths } from '@/lib/desktop-fs'
import {
addComposerAttachment,
type ComposerAttachment,
@@ -262,7 +263,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway
const pickContextPaths = useCallback(
async (kind: 'file' | 'folder') => {
- const paths = await window.hermesDesktop?.selectPaths({
+ const paths = await selectDesktopPaths({
title: kind === 'file' ? 'Add files as context' : 'Add folders as context',
defaultPath: currentCwd || undefined,
directories: kind === 'folder'
@@ -347,7 +348,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway
attachToMain(baseAttachment)
try {
- const previewUrl = await window.hermesDesktop?.readFileDataUrl(filePath)
+ const previewUrl = await readDesktopFileDataUrl(filePath)
if (previewUrl) {
addComposerAttachment({ ...baseAttachment, previewUrl })
@@ -395,7 +396,7 @@ export function useComposerActions({ activeSessionId, currentCwd, requestGateway
)
const pickImages = useCallback(async () => {
- const paths = await window.hermesDesktop?.selectPaths({
+ const paths = await selectDesktopPaths({
title: copy.attachImages,
defaultPath: currentCwd || undefined,
filters: [
diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx
index 19665341f3d..ca38d65908b 100644
--- a/apps/desktop/src/app/chat/sidebar/index.tsx
+++ b/apps/desktop/src/app/chat/sidebar/index.tsx
@@ -1149,7 +1149,8 @@ export function ChatSidebar({
const showSessionSkeletons = sessionsLoading && sortedSessions.length === 0
- const showSessionSections = showSessionSkeletons || sortedSessions.length > 0
+ const showSessionSections =
+ showSessionSkeletons || sortedSessions.length > 0 || projectModel.length > 0
// Each reorderable list reports its OWN new id order; persisting is a direct,
// typed write — no id-prefix sniffing to figure out which level moved.
@@ -1537,7 +1538,7 @@ export function ChatSidebar({
)}
- {contentVisible && !showSessionSections &&
}
+ {contentVisible && !showSessionSections && }
{contentVisible && (
@@ -1618,6 +1619,29 @@ function SidebarSessionSkeletons() {
)
}
+function SidebarBlankState({ onNewProject }: { onNewProject: () => void }) {
+ const { t } = useI18n()
+ const s = t.sidebar
+
+ return (
+
+
+
+
{s.noSessions}
+
+
+
+ )
+}
+
function SidebarPinnedEmptyState() {
const { t } = useI18n()
diff --git a/apps/desktop/src/app/chat/sidebar/project-dialog.tsx b/apps/desktop/src/app/chat/sidebar/project-dialog.tsx
index 16cbb04983d..dcd9f067f43 100644
--- a/apps/desktop/src/app/chat/sidebar/project-dialog.tsx
+++ b/apps/desktop/src/app/chat/sidebar/project-dialog.tsx
@@ -87,21 +87,25 @@ export function ProjectDialog() {
}
const pickFolder = async () => {
- const dir = await pickProjectFolder()
+ try {
+ const dir = await pickProjectFolder()
- if (!dir) {
- return
+ if (!dir) {
+ return
+ }
+
+ const projectId = state?.projectId
+
+ if (mode === 'add-folder' && projectId) {
+ await runSubmit(() => addProjectFolder(projectId, dir))
+
+ return
+ }
+
+ setFolders(prev => (prev.includes(dir) ? prev : [...prev, dir]))
+ } catch (err) {
+ notifyError(err, p.createFailed)
}
-
- const projectId = state?.projectId
-
- if (mode === 'add-folder' && projectId) {
- await runSubmit(() => addProjectFolder(projectId, dir))
-
- return
- }
-
- setFolders(prev => (prev.includes(dir) ? prev : [...prev, dir]))
}
const submit = async () => {
@@ -145,7 +149,10 @@ export function ProjectDialog() {
return (