feat(connect): list server filesystem roots/drives in directory browser (closes #57) (#100)

The directory browser could only descend from a manually-typed path
since the SDK had no way to enumerate the server's filesystem roots
(multiple drives on Windows, mount points, home dir). Add
file.roots() to sdk.ts (GET /file/roots, added server-side in
dzianisv/opencode#238) and show the results as pinned top-level chips
in DirectoryBrowserSheet that jump straight into that root.

Degrades gracefully: older servers 404 on the new endpoint, which the
SDK turns into null, normalizeRoots() turns into an empty list, and
the browser just shows no chips — manual "Jump to path" entry keeps
working exactly as before.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Den
2026-07-17 10:24:37 -07:00
committed by GitHub
parent 922cffffbd
commit 9a24cea61f
4 changed files with 193 additions and 1 deletions

View File

@@ -6,6 +6,7 @@ import { fetch as expoFetch } from "expo/fetch"
import { buildRequestHeaders } from "./headers"
import { SSEParser } from "./sse"
import { apiErrorFor } from "./api-error"
import type { FileRoot } from "./file-roots"
export { ApiAuthError, isAuthError } from "./api-error"
@@ -298,6 +299,19 @@ export function createClient(config: ClientConfig) {
const query = new URLSearchParams({ path: params.path ?? "." })
return request<FileEntry[]>(config, `/file?${query.toString()}`)
},
// Enumerate the server's filesystem roots (mounted drives, home dir)
// to seed the directory browser's pinned top-level entries. Resolves
// to null on servers that don't yet expose GET /file/roots (older
// opencode builds) so callers fall back to manual path entry instead
// of crashing; other errors propagate like any other request.
roots: async (): Promise<FileRoot[] | null> => {
try {
return await request<FileRoot[]>(config, "/file/roots")
} catch (err) {
if (err instanceof ApiError && err.status === 404) return null
throw err
}
},
},
path: {