From 2d1fc0551891823399a3f02f824661a48861c4e7 Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Mon, 10 Aug 2026 21:47:38 +0100 Subject: [PATCH] browse the directories of the server the pane is on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported from the iPad: MacBook selected, and the directory picker still listed alpha folders. Three layers all defaulted to this origin — useFilesAPI, DirPickerModal and PwdSelector — so the pane pointed one way and the pickers another. Same defect as browseDirectories in the mobile app, found this morning: a path only means something on the machine it came from, and offering another machine folders is worse than offering none, because picking one silently runs the agent somewhere that does not exist. The dir-picker cache is keyed by server too. Without it one machine tree is served from cache under the other name, which looks like the fix not working. Other useFilesAPI callers pass no server and are unchanged — the code editor and the message bubble still read this origin exactly as before. Co-Authored-By: Claude Opus 5 --- .../src/apps/ChatHistory/DirPickerModal.tsx | 10 +++++++--- .../officerdev/src/apps/ChatHistory/PwdSelector.tsx | 8 +++++--- .../officerdev/src/apps/ChatHistory/SessionList.tsx | 1 + src/workspaces/officerdev/src/hooks/useFilesAPI.ts | 12 ++++++++++-- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx b/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx index 01b92e60..37432966 100644 --- a/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx +++ b/src/workspaces/officerdev/src/apps/ChatHistory/DirPickerModal.tsx @@ -8,12 +8,14 @@ type DirPickerModalProps = { open: boolean; onClose: () => void; onSelect: (absPath: string) => void; + /** Whose filesystem to browse. Absent = this origin. */ + serverId?: string | null; }; // A simplified file-browser modal for picking a working directory (returns an absolute path). // Navigates within the home root; dirs elsewhere are reachable via the selector's free-text field. -export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) => { - const api = useFilesAPI('home'); +export const DirPickerModal = ({ open, onClose, onSelect, serverId }: DirPickerModalProps) => { + const api = useFilesAPI('home', serverId); const [path, setPath] = useState('/'); // root-relative, always starts with '/' const [creating, setCreating] = useState(false); const [newName, setNewName] = useState(''); @@ -23,7 +25,9 @@ export const DirPickerModal = ({ open, onClose, onSelect }: DirPickerModalProps) const [showHidden, setShowHidden] = useState(false); const { data, isLoading, refetch } = useQuery({ - queryKey: ['dir-picker', path], + // Server in the key: two machines have different trees, and without it one machine's folders + // are served from cache under the other's name. + queryKey: ['dir-picker', path, serverId ?? null], queryFn: () => api.listDir(path), enabled: open, }); diff --git a/src/workspaces/officerdev/src/apps/ChatHistory/PwdSelector.tsx b/src/workspaces/officerdev/src/apps/ChatHistory/PwdSelector.tsx index 4748faa0..6799cf22 100644 --- a/src/workspaces/officerdev/src/apps/ChatHistory/PwdSelector.tsx +++ b/src/workspaces/officerdev/src/apps/ChatHistory/PwdSelector.tsx @@ -6,14 +6,16 @@ import { DirPickerModal } from './DirPickerModal'; type PwdSelectorProps = { value: string | null; // null = the default general_chat_sessions dir onChange: (cwd: string | null) => void; + /** Which Officer's directories to offer. Absent = this origin. */ + serverId?: string | null; }; // A shorter, friendlier label for a working directory. const shorten = (cwd: string) => cwd.replace(/^\/home\/[^/]+/, '~'); const basename = (cwd: string) => cwd.split('/').filter(Boolean).pop() ?? cwd; -export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => { - const { pwds, defaultCwd } = useChatPwds(); +export const PwdSelector = ({ value, onChange, serverId }: PwdSelectorProps) => { + const { pwds, defaultCwd } = useChatPwds(serverId); const [open, setOpen] = useState(false); const [browse, setBrowse] = useState(false); const [custom, setCustom] = useState(''); @@ -96,7 +98,7 @@ export const PwdSelector = ({ value, onChange }: PwdSelectorProps) => { )} - setBrowse(false)} onSelect={(p) => pick(p)} /> + setBrowse(false)} onSelect={(p) => pick(p)} serverId={serverId} /> ); }; diff --git a/src/workspaces/officerdev/src/apps/ChatHistory/SessionList.tsx b/src/workspaces/officerdev/src/apps/ChatHistory/SessionList.tsx index 75157bf2..99629874 100644 --- a/src/workspaces/officerdev/src/apps/ChatHistory/SessionList.tsx +++ b/src/workspaces/officerdev/src/apps/ChatHistory/SessionList.tsx @@ -95,6 +95,7 @@ export const SessionList = () => { }} /> { setSelected(null); // sessions belong to a cwd — clear the open one when switching diff --git a/src/workspaces/officerdev/src/hooks/useFilesAPI.ts b/src/workspaces/officerdev/src/hooks/useFilesAPI.ts index a5f9ea03..e5b9df0b 100644 --- a/src/workspaces/officerdev/src/hooks/useFilesAPI.ts +++ b/src/workspaces/officerdev/src/hooks/useFilesAPI.ts @@ -1,9 +1,17 @@ import { useClient, getHeaders } from 'hooks/useClient'; +import { useServerClient } from 'hooks/useServerClient'; const API_URL = '/api'; -export const useFilesAPI = (root: string = 'home') => { - const client = useClient(); +/** + * `serverId` names another Officer; absent is this origin, which is every existing caller. + * + * Load-bearing for the chat directory pickers: a path only means something on the machine it came from, + * so browsing without it showed THIS server's folders while the pane was pointed at another — the exact + * bug the mobile app has with `browseDirectories`. + */ +export const useFilesAPI = (root: string = 'home', serverId?: string | null) => { + const client = useServerClient(serverId); const rootParam = root !== 'home' ? `root=${encodeURIComponent(root)}` : ''; const withRoot = (url: string) => rootParam ? (url.includes('?') ? `${url}&${rootParam}` : `${url}?${rootParam}`) : url;