Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4e1395b
Merge pull request #719 from KunAgent/develop
XingYu-Zhong Jul 3, 2026
d7f4be3
Merge pull request #724 from KunAgent/develop
XingYu-Zhong Jul 3, 2026
7019c35
Merge pull request #792 from KunAgent/develop
XingYu-Zhong Jul 7, 2026
777e343
Merge pull request #794 from KunAgent/develop
XingYu-Zhong Jul 7, 2026
71dea37
docs: plan issue 781 document management improvements
luoye520ww Jul 8, 2026
b022928
chore: remove accidental planning note
luoye520ww Jul 8, 2026
0b1a098
feat(files): broaden assistant file reference detection
luoye520ww Jul 8, 2026
4c0967c
feat(files): linkify generated file paths in rendered output
luoye520ww Jul 8, 2026
67108ea
feat(files): install document usability hooks
luoye520ww Jul 8, 2026
f7bb5ac
feat(files): keep and enhance preview tabs
luoye520ww Jul 8, 2026
bc2fbbb
feat(files): add recent file shortcuts and drag references
luoye520ww Jul 8, 2026
c7eca7a
fix(files): remove cross-workspace preview restore and live-clone reader
luoye520ww Jul 8, 2026
f5844f8
fix(files): expose workspace entry metadata for real sorting
luoye520ww Jul 8, 2026
7972061
fix(files): sort file tree through React state
luoye520ww Jul 8, 2026
75f36d1
fix(files): restore workspace file result types
luoye520ww Jul 8, 2026
09f1c6d
fix(files): export metadata-backed directory listing
luoye520ww Jul 8, 2026
04ce7b7
fix(files): attach mtime metadata to file tree entries
luoye520ww Jul 8, 2026
b6c954d
fix(files): scan workspace for recent modified files
luoye520ww Jul 8, 2026
cf93783
fix(files): scope preview tab state by page context
luoye520ww Jul 8, 2026
64e237b
test(files): cover modified sorting helpers
luoye520ww Jul 8, 2026
13acb04
fix(files): annotate directory entries with filesystem metadata
luoye520ww Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/main/services/workspace-file-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { stat } from 'node:fs/promises'
import type {
WorkspaceDirectoryListResult,
WorkspaceDirectoryTarget,
WorkspaceEntry
} from '../../shared/workspace-file'
import { listWorkspaceDirectory as listWorkspaceDirectoryWithoutMetadata } from './workspace-files'

async function withEntryMetadata(entry: WorkspaceEntry): Promise<WorkspaceEntry> {
try {
const info = await stat(entry.path)
return {
...entry,
mtimeMs: info.mtimeMs,
size: info.isFile() ? info.size : 0
}
} catch {
return entry
}
}

export async function listWorkspaceDirectory(
payload: WorkspaceDirectoryTarget
): Promise<WorkspaceDirectoryListResult> {
const result = await listWorkspaceDirectoryWithoutMetadata(payload)
if (!result.ok) return result
return {
...result,
entries: await Promise.all(result.entries.map(withEntryMetadata))
}
}
1 change: 1 addition & 0 deletions src/main/services/workspace-service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './workspace-paths'
export * from './workspace-editors'
export * from './workspace-files'
export { listWorkspaceDirectory } from './workspace-file-metadata'
1 change: 1 addition & 0 deletions src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { lazy, Suspense } from 'react'
import { AppErrorBoundary } from './components/AppErrorBoundary'
import './lib/issue-781-document-usability'

const AppShell = lazy(() => import('./AppShell'))

Expand Down
30 changes: 28 additions & 2 deletions src/renderer/src/components/chat/ChatFileTreePanel.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { describe, expect, it } from 'vitest'
import type { WorkspaceEntry } from '@shared/workspace-file'
import {
compareChatFileTreeEntriesByModified,
formatChatFileTreeUnsupportedMessage,
isChatFileTreeIgnoredDirectory,
isChatFileTreePreviewableEntry
isChatFileTreePreviewableEntry,
sortChatFileTreeEntries
} from './ChatFileTreePanel'

function entry(overrides: Partial<WorkspaceEntry> & Pick<WorkspaceEntry, 'name' | 'type'>): WorkspaceEntry {
return {
name: overrides.name,
type: overrides.type,
path: overrides.path ?? `/tmp/project/${overrides.name}`,
ext: overrides.ext ?? ''
ext: overrides.ext ?? '',
...(overrides.mtimeMs === undefined ? {} : { mtimeMs: overrides.mtimeMs }),
...(overrides.size === undefined ? {} : { size: overrides.size })
}
}

Expand All @@ -31,4 +35,26 @@ describe('ChatFileTreePanel helpers', () => {
it('formats unsupported preview titles without leaking UI state', () => {
expect(formatChatFileTreeUnsupportedMessage('logo.png')).toContain('logo.png')
})

it('sorts files by newest mtime before falling back to name', () => {
expect([
entry({ name: 'old.md', type: 'file', mtimeMs: 100 }),
entry({ name: 'new.md', type: 'file', mtimeMs: 300 }),
entry({ name: 'same-b.md', type: 'file', mtimeMs: 200 }),
entry({ name: 'same-a.md', type: 'file', mtimeMs: 200 })
].sort(compareChatFileTreeEntriesByModified).map((item) => item.name)).toEqual([
'new.md',
'same-a.md',
'same-b.md',
'old.md'
])
})

it('keeps directories before files in modified sort mode', () => {
expect(sortChatFileTreeEntries([
entry({ name: 'new.md', type: 'file', mtimeMs: 300 }),
entry({ name: 'docs', type: 'directory', mtimeMs: 100 }),
entry({ name: 'old.md', type: 'file', mtimeMs: 50 })
], 'modified').map((item) => item.name)).toEqual(['docs', 'new.md', 'old.md'])
})
})
Loading