diff --git a/.gitignore b/.gitignore index 0c90caa8..20178d76 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ local-dev* *.njsproj *.sln *.sw? +.opencode/plans/* diff --git a/packages/ui/src/components/session/DirectoryTree.tsx b/packages/ui/src/components/session/DirectoryTree.tsx index b3a02e08..0e6d05eb 100644 --- a/packages/ui/src/components/session/DirectoryTree.tsx +++ b/packages/ui/src/components/session/DirectoryTree.tsx @@ -582,7 +582,7 @@ export const DirectoryTree: React.FC = ({ const fullPath = `${creatingInPath}/${dirName}`; try { - await opencodeClient.createDirectory(fullPath); + await opencodeClient.createDirectory(fullPath, { allowOutsideWorkspace: true }); const children = await loadDirectory(creatingInPath); const updateItems = (items: DirectoryItem[]): DirectoryItem[] => { diff --git a/packages/ui/src/lib/opencode/client.ts b/packages/ui/src/lib/opencode/client.ts index 5727380b..44cce646 100644 --- a/packages/ui/src/lib/opencode/client.ts +++ b/packages/ui/src/lib/opencode/client.ts @@ -1752,7 +1752,10 @@ class OpencodeService { } // File System Operations - async createDirectory(dirPath: string): Promise<{ success: boolean; path: string }> { + async createDirectory( + dirPath: string, + options?: { allowOutsideWorkspace?: boolean } + ): Promise<{ success: boolean; path: string }> { const desktopFiles = getDesktopFilesApi(); if (desktopFiles?.createDirectory) { try { @@ -1763,12 +1766,17 @@ class OpencodeService { } } + const payload = { + path: dirPath, + ...(options?.allowOutsideWorkspace ? { allowOutsideWorkspace: true } : {}), + }; + const response = await fetch(`${this.baseUrl}/fs/mkdir`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ path: dirPath }), + body: JSON.stringify(payload), }); if (!response.ok) { diff --git a/packages/web/server/index.js b/packages/web/server/index.js index 18c572d4..8d0ea3a2 100644 --- a/packages/web/server/index.js +++ b/packages/web/server/index.js @@ -6151,20 +6151,27 @@ async function main(options = {}) { app.post('/api/fs/mkdir', async (req, res) => { try { - const { path: dirPath } = req.body; + const { path: dirPath, allowOutsideWorkspace } = req.body ?? {}; - if (!dirPath) { + if (typeof dirPath !== 'string' || !dirPath.trim()) { return res.status(400).json({ error: 'Path is required' }); } - const resolved = await resolveWorkspacePathFromContext(req, dirPath); - if (!resolved.ok) { - return res.status(400).json({ error: resolved.error }); + let resolvedPath = ''; + + if (allowOutsideWorkspace) { + resolvedPath = path.resolve(normalizeDirectoryPath(dirPath)); + } else { + const resolved = await resolveWorkspacePathFromContext(req, dirPath); + if (!resolved.ok) { + return res.status(400).json({ error: resolved.error }); + } + resolvedPath = resolved.resolved; } - await fsPromises.mkdir(resolved.resolved, { recursive: true }); + await fsPromises.mkdir(resolvedPath, { recursive: true }); - res.json({ success: true, path: resolved.resolved }); + res.json({ success: true, path: resolvedPath }); } catch (error) { console.error('Failed to create directory:', error); res.status(500).json({ error: error.message || 'Failed to create directory' });