Skip to content

fix(uploads): keep Desktop Local uploads in the project and preview them via the sidecar - #173

Merged
akemmanuel merged 1 commit into
akemmanuel:masterfrom
touch2be:fix/desktop-upload-previews
Oct 23, 2026
Merged

akemmanuel merged 1 commit into
akemmanuel:masterfrom
touch2be:fix/desktop-upload-previews

Conversation

@touch2be

Copy link
Copy Markdown
Collaborator

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:

  1. Wrong Host URL for transcript previews. attachmentBaseUrl is workspace.serverUrl. For the Desktop Local workspace that is DEFAULT_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.
  2. Uploads outside the allowed roots. Unrestricted Hosts (Desktop Local) stored uploads in os.tmpdir()/opengui-uploads. /api/fs/file only serves files inside OPENGUI_ALLOWED_ROOTS, which Desktop defaults to $HOME. So even against the correct sidecar port, the request fails with 400 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 their serverUrl is 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 a directory is 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.
  • The upload directory gets a .gitignore containing * (written once, never overwritten). Pasted screenshots therefore stay out of git status without touching the user's own .gitignore. This also benefits restricted Hosts.
  • resolveAttachmentBaseUrl (src/lib/attachment-src.ts): Desktop Local workspaces resolve to electronAPI.backendUrl, all others keep workspace.serverUrl. HostProvider uses it for attachmentBaseUrl, so transcript thumbnails and the lightbox reach the sidecar. While the sidecar URL is unknown it returns null, which falls back to the existing file:// rendering.
  • ADR 0002 now describes the new storage location.

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 .gitignore is 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 to null while the sidecar URL is unknown.

pnpm run check, the full vp test run (243 files / 1573 tests) and pnpm run slop-check all pass. I have not yet tested this in a running packaged Desktop build.

🤖 Generated with Claude Code

…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>
@akemmanuel
akemmanuel merged commit 8e6874d into akemmanuel:master Oct 23, 2026
2 checks passed
@akemmanuel akemmanuel mentioned this pull request Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants