diff --git a/src/renderer/src/components/right-sidebar/FileExplorer.tsx b/src/renderer/src/components/right-sidebar/FileExplorer.tsx index bf8eb2736c..ff23635395 100644 --- a/src/renderer/src/components/right-sidebar/FileExplorer.tsx +++ b/src/renderer/src/components/right-sidebar/FileExplorer.tsx @@ -479,6 +479,7 @@ function FileExplorerFiles(): React.JSX.Element { }, []) const { handleClick, handleDoubleClick, handleWheelCapture } = useFileExplorerHandlers({ activeWorktreeId, + runtimeEnvironmentId: activeRuntimeEnvironmentId, openFile, makePreviewFilePermanent, toggleDir: hasNameFilter ? handleToggleNameFilterDir : toggleDir, diff --git a/src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx b/src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx index 8752302e75..ded3aa0cb6 100644 --- a/src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx +++ b/src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx @@ -112,6 +112,7 @@ let capturedHandlers: ReturnType | null = null function HandlersProbe({ scrollRef }: { scrollRef: React.RefObject }): null { capturedHandlers = useFileExplorerHandlers({ activeWorktreeId: 'wt-1', + runtimeEnvironmentId: null, openFile: vi.fn(), makePreviewFilePermanent: vi.fn(), toggleDir: vi.fn(), diff --git a/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.test.ts b/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.test.ts index e4514f48b2..22c4808c8a 100644 --- a/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.test.ts +++ b/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.test.ts @@ -72,6 +72,7 @@ describe('activateFileExplorerNode', () => { await activateFileExplorerNode({ node: symlinkNode, activeWorktreeId: 'wt-1', + runtimeEnvironmentId: 'runtime-env-1', openFile, toggleDir: vi.fn(), loadDir: vi.fn(), @@ -85,10 +86,42 @@ describe('activateFileExplorerNode', () => { filePath: '/repo/linked-docs', relativePath: 'linked-docs', worktreeId: 'wt-1', + runtimeEnvironmentId: 'runtime-env-1', language: expect.any(String), mode: 'edit' }, - { preview: true } + { preview: true, suppressActiveRuntimeFallback: false } + ) + }) + + it('opens local files without runtime fallback when no runtime owner is set', async () => { + const fileNode: TreeNode = { + name: 'README.md', + path: '/repo/README.md', + relativePath: 'README.md', + isDirectory: false, + depth: 0 + } + const openFile = vi.fn() + + await activateFileExplorerNode({ + node: fileNode, + activeWorktreeId: 'wt-1', + runtimeEnvironmentId: null, + openFile, + toggleDir: vi.fn(), + loadDir: vi.fn(), + statPath: vi.fn(), + markPathAsDirectory: vi.fn(), + setSelectedPath: vi.fn() + }) + + expect(openFile).toHaveBeenCalledWith( + expect.objectContaining({ + filePath: '/repo/README.md', + runtimeEnvironmentId: undefined + }), + { preview: true, suppressActiveRuntimeFallback: true } ) }) }) diff --git a/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.ts b/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.ts index 4795cc4e4b..d6ddc4b977 100644 --- a/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.ts +++ b/src/renderer/src/components/right-sidebar/useFileExplorerHandlers.ts @@ -9,6 +9,7 @@ import { translate } from '@/i18n/i18n' type UseFileExplorerHandlersParams = { activeWorktreeId: string | null + runtimeEnvironmentId?: string | null openFile: ( params: { filePath: string @@ -16,8 +17,9 @@ type UseFileExplorerHandlersParams = { worktreeId: string language: string mode: 'edit' + runtimeEnvironmentId?: string | null }, - options?: { preview?: boolean } + options?: { preview?: boolean; suppressActiveRuntimeFallback?: boolean } ) => void makePreviewFilePermanent: (filePath: string) => void toggleDir: (worktreeId: string, dirPath: string) => void @@ -45,6 +47,7 @@ type OpenFileOptions = Parameters[1] export async function activateFileExplorerNode(args: { node: TreeNode activeWorktreeId: string | null + runtimeEnvironmentId?: string | null openFile: (params: OpenFileParams, options?: OpenFileOptions) => void toggleDir: (worktreeId: string, dirPath: string) => void canToggleDirectories?: boolean @@ -56,6 +59,7 @@ export async function activateFileExplorerNode(args: { const { node, activeWorktreeId, + runtimeEnvironmentId, openFile, toggleDir, canToggleDirectories = true, @@ -116,15 +120,22 @@ export async function activateFileExplorerNode(args: { filePath: node.path, relativePath: node.relativePath, worktreeId: activeWorktreeId, + runtimeEnvironmentId: runtimeEnvironmentId ?? undefined, language: detectLanguage(node.name), mode: 'edit' }, - { preview: true } + { + preview: true, + // Why: explicit local opens must not inherit the active runtime, so we + // encode "no runtime owner" via the fallback-suppression option. + suppressActiveRuntimeFallback: runtimeEnvironmentId === null + } ) } export function useFileExplorerHandlers({ activeWorktreeId, + runtimeEnvironmentId, openFile, makePreviewFilePermanent, toggleDir, @@ -140,6 +151,7 @@ export function useFileExplorerHandlers({ void activateFileExplorerNode({ node, activeWorktreeId, + runtimeEnvironmentId, openFile, toggleDir, canToggleDirectories, @@ -151,6 +163,7 @@ export function useFileExplorerHandlers({ }, [ activeWorktreeId, + runtimeEnvironmentId, canToggleDirectories, loadDir, markPathAsDirectory, diff --git a/src/renderer/src/components/right-sidebar/useFileExplorerInlineInput.ts b/src/renderer/src/components/right-sidebar/useFileExplorerInlineInput.ts index aae50da62d..fb8f87c690 100644 --- a/src/renderer/src/components/right-sidebar/useFileExplorerInlineInput.ts +++ b/src/renderer/src/components/right-sidebar/useFileExplorerInlineInput.ts @@ -158,13 +158,19 @@ export function useFileExplorerInlineInput({ } await refreshDir(inlineInput.parentPath) if (inlineInput.type === 'file') { - openFile({ - filePath: fullPath, - relativePath: worktreePath ? fullPath.slice(worktreePath.length + 1) : name, - worktreeId: activeWorktreeId, - language: detectLanguage(name), - mode: 'edit' - }) + const runtimeEnvironmentId = + fileContext.settings.activeRuntimeEnvironmentId?.trim() || null + openFile( + { + filePath: fullPath, + relativePath: worktreePath ? fullPath.slice(worktreePath.length + 1) : name, + worktreeId: activeWorktreeId, + runtimeEnvironmentId: runtimeEnvironmentId ?? undefined, + language: detectLanguage(name), + mode: 'edit' + }, + { suppressActiveRuntimeFallback: runtimeEnvironmentId === null } + ) } } catch (err) { // Refresh the directory even on failure so the tree stays consistent