Repository navigation
fix(uploads): keep Desktop Local uploads in the project and preview them via the sidecar - #173
Merged
akemmanuel merged 1 commit intoOct 23, 2026
Conversation
…hem via the sidecar Desktop transcripts showed broken image tiles for uploaded screenshots while hosted Web worked. Two Desktop-only causes: - Transcript previews used the stored workspace URL (127.0.0.1:4096), but the Desktop Local Host runs as a sidecar on a per-launch port. - Unrestricted uploads went to the OS temp dir, which is outside the default allowed roots (home) and is wiped on reboot, so /api/fs/file rejected them. Uploads with a Project directory now always land in <project>/.opengui-uploads (self-ignored by git), matching restricted Hosts. Transcript previews resolve the sidecar URL for Desktop Local workspaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In the Desktop app, uploaded screenshots in the transcript show only a broken image tile. The prompt box still renders them. Hosted Web (e.g. a server deployment with identity) works correctly.
There are two Desktop-only causes:
attachmentBaseUrlisworkspace.serverUrl. For the Desktop Local workspace that isDEFAULT_SERVER_URL(http://127.0.0.1:4096). The Desktop Local Host, however, runs as a sidecar on a per-launch port (findAvailablePort), so preview requests never reach it.os.tmpdir()/opengui-uploads./api/fs/fileonly serves files insideOPENGUI_ALLOWED_ROOTS, which Desktop defaults to$HOME. So even against the correct sidecar port, the request fails with400 Path outside OPENGUI_ALLOWED_ROOTS. The temp dir is also wiped on reboot, so older transcripts lose their images in any case.Hosted Web is unaffected because restricted Hosts already write to
<project>/.opengui-uploads/, and theirserverUrlis the real Host.The prompt box hid both causes: in Desktop Local it renders
file://URLs directly instead of going through the Host.Change
POST /api/fs/upload: if adirectoryis provided, uploads always go to<project>/.opengui-uploads/, whether or not the Host is restricted. The same path authorization as before applies. On Desktop Local that is the local policy with its allowed roots. Without a directory, unrestricted Hosts still fall back to the temp dir, and restricted Hosts still require a directory..gitignorecontaining*(written once, never overwritten). Pasted screenshots therefore stay out ofgit statuswithout touching the user's own.gitignore. This also benefits restricted Hosts.resolveAttachmentBaseUrl(src/lib/attachment-src.ts): Desktop Local workspaces resolve toelectronAPI.backendUrl, all others keepworkspace.serverUrl.HostProvideruses it forattachmentBaseUrl, so transcript thumbnails and the lightbox reach the sidecar. While the sidecar URL is unknown it returnsnull, which falls back to the existingfile://rendering.The prompt box upload and preview path is intentionally unchanged. Its
file://previews still cover Prompts without a Project, whose uploads remain in the temp dir.Tests
path-enforcement.routes.test.ts: a Desktop Local actor with the local policy uploads into<project>/.opengui-uploads/. The test checks that the.gitignoreis created and that a second upload keeps working. The uploaded file can be read back through/api/fs/file, and a directory outside the allowed roots is rejected with 403. The test fails without the backend change.attachment-src.test.ts: the resolver uses the sidecar on Desktop Local and keeps remote and Web URLs. It falls back tonullwhile the sidecar URL is unknown.pnpm run check, the fullvp testrun (243 files / 1573 tests) andpnpm run slop-checkall pass. I have not yet tested this in a running packaged Desktop build.🤖 Generated with Claude Code