cc-haha/desktop/src/api/filesystem.ts
程序员阿江(Relakkes) f41e786748 Align desktop file mentions with CLI search
Desktop @ file search was recursively walking the filesystem with a local skip list, which let Python and Node generated directories leak into results and diverged from CLI behavior. Route candidate discovery through the same git-first model: tracked files, untracked files with exclude-standard, and ripgrep fallback for non-git folders, then derive selectable directories from those candidates.

Constraint: Desktop picker must select both files and directories without surfacing ignored project artifacts.
Constraint: No new dependencies; reuse the existing git, ripgrep, settings, and ignore utilities.
Rejected: Maintain a hardcoded directory denylist | it would drift from CLI and miss project-specific ignore rules.
Rejected: Full recursive readdir scanning | it ignores git index semantics and makes large dependency trees visible.
Confidence: high
Scope-risk: moderate
Directive: Keep desktop @ file candidate discovery aligned with src/hooks/fileSuggestions.ts before changing ranking or ignore behavior.
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: cd desktop && bun run test -- FileSearchMenu.test.tsx ChatInput.test.tsx
Tested: cd desktop && bun run lint && bun run test -- --run && bun run build
Tested: bun run check:server
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Native Windows/Linux manual UI smoke; path handling relies on cross-platform git/ripgrep wrappers and normalized relative paths.
2026-05-13 10:38:13 +08:00

32 lines
814 B
TypeScript

import { api } from './client'
type DirEntry = {
name: string
path: string
isDirectory: boolean
relativePath?: string
}
type BrowseResult = {
currentPath: string
parentPath: string
entries: DirEntry[]
query?: string
}
export const filesystemApi = {
browse(path?: string, options?: { includeFiles?: boolean }) {
const q = new URLSearchParams()
if (path) q.set('path', path)
if (options?.includeFiles) q.set('includeFiles', 'true')
const qs = q.toString()
return api.get<BrowseResult>(`/api/filesystem/browse${qs ? `?${qs}` : ''}`)
},
search(query: string, cwd?: string) {
const q = new URLSearchParams({ search: query, maxResults: '200', includeFiles: 'true' })
if (cwd) q.set('path', cwd)
return api.get<BrowseResult>(`/api/filesystem/browse?${q}`)
},
}