diff --git a/src/__tests__/api-clients.test.ts b/src/__tests__/api-clients.test.ts index 9a5bb7e..b936405 100644 --- a/src/__tests__/api-clients.test.ts +++ b/src/__tests__/api-clients.test.ts @@ -1362,6 +1362,66 @@ describe('Auxiliary API clients', () => { ); }); + it('FileClient forwards includeHidden to the home and search_subdirs endpoints', async () => { + global.fetch = jest + .fn() + .mockResolvedValueOnce( + new Response(JSON.stringify({ home: '/workspace' }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }) + ) + .mockResolvedValueOnce( + new Response(JSON.stringify({ items: [], next_page_id: null }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }) + ); + + const client = new FileClient({ host: 'http://example.com' }); + await expect(client.getHome({ includeHidden: true })).resolves.toEqual({ + home: '/workspace', + }); + await client.searchSubdirectories('/workspace', { includeHidden: true }); + + expect(global.fetch).toHaveBeenNthCalledWith( + 1, + 'http://example.com/api/file/home?include_hidden=true', + expect.objectContaining({ method: 'GET' }) + ); + expect(global.fetch).toHaveBeenNthCalledWith( + 2, + 'http://example.com/api/file/search_subdirs?path=%2Fworkspace&include_hidden=true', + expect.objectContaining({ method: 'GET' }) + ); + }); + + it('FileClient omits include_hidden when includeHidden is not set', async () => { + global.fetch = jest + .fn() + .mockResolvedValueOnce( + new Response(JSON.stringify({ home: '/workspace' }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }) + ) + .mockResolvedValueOnce( + new Response(JSON.stringify({ items: [], next_page_id: null }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }) + ); + + const client = new FileClient({ host: 'http://example.com' }); + await client.getHome(); + await client.searchSubdirectories('/workspace'); + + expect((global.fetch as jest.Mock).mock.calls[0][0]).toBe('http://example.com/api/file/home'); + expect((global.fetch as jest.Mock).mock.calls[1][0]).toBe( + 'http://example.com/api/file/search_subdirs?path=%2Fworkspace' + ); + }); + it('ConversationClient wraps agent-canvas conversation endpoints', async () => { global.fetch = jest.fn().mockImplementation(() => Promise.resolve( diff --git a/src/client/file-client.ts b/src/client/file-client.ts index 3686af0..30d2767 100644 --- a/src/client/file-client.ts +++ b/src/client/file-client.ts @@ -1,5 +1,6 @@ import { HttpClient } from './http-client'; import type { + FileHomeOptions, FileHomeResponse, FileSearchSubdirsOptions, FileSubdirectoryPage, @@ -38,13 +39,18 @@ export class FileClient { path, page_id: options.pageId, limit: options.limit, + include_hidden: options.includeHidden || undefined, }, }); return response.data; } - async getHome(): Promise { - const response = await this.client.get('/api/file/home'); + async getHome(options: FileHomeOptions = {}): Promise { + const response = await this.client.get('/api/file/home', { + params: { + include_hidden: options.includeHidden || undefined, + }, + }); return response.data; } diff --git a/src/models/api.ts b/src/models/api.ts index 83f69f8..21194c8 100644 --- a/src/models/api.ts +++ b/src/models/api.ts @@ -289,13 +289,27 @@ export interface FileSubdirectoryPage { next_page_id: string | null; } +export interface FileBrowserEntry { + label: string; + path: string; +} + export interface FileHomeResponse { home: string; + favorites?: FileBrowserEntry[]; + locations?: FileBrowserEntry[]; +} + +export interface FileHomeOptions { + /** Include hidden top-level directories in the response's `favorites`. */ + includeHidden?: boolean; } export interface FileSearchSubdirsOptions { pageId?: string | null; limit?: number; + /** Include hidden subdirectories (names starting with '.'). */ + includeHidden?: boolean; } export interface CloudProxyRequest {