From 41d5cc3c12816546bef9feda38f3f89397da6510 Mon Sep 17 00:00:00 2001 From: Hibryda Date: Sun, 22 Mar 2026 12:11:39 +0100 Subject: [PATCH] fix(electrobun): PathBrowser uses unguarded files.browse RPC (dirs only) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - files.browse: new RPC handler — unguarded directory listing, returns only directories (no file content access). Used by PathBrowser wizard. - PathBrowser: uses files.browse instead of files.list (was blocked by guardPath "access denied: path outside allowed project directories") - Home dir resolved via files.homeDir RPC (not process.env.HOME) Note: GTK native dialog title/theme/sort controlled by Electrobun's native wrapper — canChooseFiles:false should set SELECT_FOLDER action but may need upstream fix for correct title. --- ui-electrobun/src/bun/handlers/files-handlers.ts | 16 ++++++++++++++++ ui-electrobun/src/mainview/PathBrowser.svelte | 2 +- ui-electrobun/src/shared/pty-rpc-schema.ts | 5 +++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ui-electrobun/src/bun/handlers/files-handlers.ts b/ui-electrobun/src/bun/handlers/files-handlers.ts index 7d0d17a..6f5b55d 100644 --- a/ui-electrobun/src/bun/handlers/files-handlers.ts +++ b/ui-electrobun/src/bun/handlers/files-handlers.ts @@ -43,6 +43,22 @@ export function createFilesHandlers() { } }, + // Unguarded directory listing for the PathBrowser (wizard). + // Only returns dir names — no file content access. + "files.browse": async ({ path: dirPath }: { path: string }) => { + try { + const resolved = path.resolve(dirPath.replace(/^~/, process.env.HOME || "/home")); + const dirents = fs.readdirSync(resolved, { withFileTypes: true }); + const entries = dirents + .filter((d) => !d.name.startsWith(".") && d.isDirectory()) + .map((d) => ({ name: d.name, type: "dir" as const, size: 0 })) + .sort((a, b) => a.name.localeCompare(b.name)); + return { entries }; + } catch (err) { + return { entries: [], error: err instanceof Error ? err.message : String(err) }; + } + }, + "files.read": async ({ path: filePath }: { path: string }) => { const guard = guardPath(filePath); if (!guard.valid) { diff --git a/ui-electrobun/src/mainview/PathBrowser.svelte b/ui-electrobun/src/mainview/PathBrowser.svelte index 07303a7..1c82a07 100644 --- a/ui-electrobun/src/mainview/PathBrowser.svelte +++ b/ui-electrobun/src/mainview/PathBrowser.svelte @@ -56,7 +56,7 @@ try { const home = await resolveHome(); const expandedPath = dirPath.replace(/^~/, home); - const result = await appRpc.request['files.list']({ path: expandedPath }); + const result = await appRpc.request['files.browse']({ path: expandedPath }); if (result?.error) { error = result.error; entries = []; diff --git a/ui-electrobun/src/shared/pty-rpc-schema.ts b/ui-electrobun/src/shared/pty-rpc-schema.ts index ccc9b2a..7ced58f 100644 --- a/ui-electrobun/src/shared/pty-rpc-schema.ts +++ b/ui-electrobun/src/shared/pty-rpc-schema.ts @@ -146,6 +146,11 @@ export type PtyRPCRequests = { error?: string; }; }; + /** Unguarded directory listing for PathBrowser (dirs only, no file content) */ + "files.browse": { + params: { path: string }; + response: { entries: { name: string; type: 'dir'; size: number }[]; error?: string }; + }; /** Native folder picker dialog */ "files.pickDirectory": { params: { startingFolder?: string };