Skip to content

feat(web): import themes from local .vsix extension packages - #8419

Open
ipanasenko wants to merge 2 commits into
pingdotgg:mainfrom
ipanasenko:t3code/add-custom-theme-from-vsix
Open

feat(web): import themes from local .vsix extension packages#8419
ipanasenko wants to merge 2 commits into
pingdotgg:mainfrom
ipanasenko:t3code/add-custom-theme-from-vsix

Conversation

@ipanasenko

@ipanasenko ipanasenko commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Problem

A theme the user already owns as a .vsix file (paid themes like Dracula Pro, private packages, anything not on Open VSX) has no import path. The Add a theme dialog accepts loose T3 Code / VS Code .json files, and the search only covers open-source Open VSX extensions.

Fix

Screen.Recording.2026-08-27.at.6.46.25.PM.mov

============ TEXT BELOW IS GENERATED BY FABLE ========================================

  • Extract the VSIX/ZIP machinery (bomb-safe ZIP directory inspection, path traversal guards, JSONC include resolution, contribution parsing, light/dark pairing) from openVsxThemes.ts into a new vsixThemePackage.ts and rebuild the Open VSX import on top of it, so the two paths cannot drift.
  • The import dialog accepts a dropped or picked .vsix. Every contributed color theme imports as one collection, so re-importing the same extension offers an update (with the existing local-edits warning) instead of piling up copies.
  • Local packages skip the registry-only gates: no SPDX license allowlist (the user already has the file) and no checksum (there is no registry to check against). All archive-safety limits stay: 20 MB package cap, 5,000-entry / 100 MB / 200x-ratio ZIP caps, 256 KB per theme file, 40 themes per extension, path and include-depth checks.
  • Local ids use their own prefix (vsix-theme-) and collection namespace (local-vsix:), so a local import never collides with the same extension installed from Open VSX.
  • The desktop native picker lists .vsix and sends package bytes base64-encoded over IPC (PickedThemeFile.contentBase64), matching how other binary crosses the bridge.

Surfaces

  • Web and desktop share the dialog; desktop additionally gets the native picker path. Mobile has no theme import UI, so nothing to do there.
  • One .vsix per import: a package expands into a collection with its own update prompt, so mixing it into a multi-file JSON batch would need a second conflict flow. Multi-select with a .vsix shows a clear error.
  • No docs page exists for themes yet; feat(desktop): apply theme files from command line #8080 adds docs/user/themes.md, and this feature should be added there once either lands.

Note for review: overlaps textually (not logically) with #8063 — that PR hardens the Open VSX network path, this one relocates the ZIP layer it sits on. Whichever lands second rebases mechanically.

Built with Claude (Fable 5) via Claude Code.

Note

Add local .vsix theme package import to ThemeImportDialog

  • Desktop file picker (window.pickThemeFiles) now accepts .vsix files, enforces a 20 MB cap (PICKED_THEME_PACKAGE_MAX_BYTES), and sends binary content base64-encoded via a new contentBase64 field on the PickedThemeFile IPC contract.
  • New vsixThemePackage.ts module safely opens ZIP archives (entry count, total size, compression ratio checks), parses the extension manifest, extracts contributed themes with deterministic IDs, and pairs light/dark variants.
  • ThemeImportDialog.tsx routes .vsix files to single-package import, reads bytes from the file or desktop bridge, and prompts to update when the collection is already installed.
  • Behavioral Change: importing a .vsix for an already-installed collection replaces it via replaceCustomThemeCollection, dropping any local edits; only one .vsix may be imported at a time.

Macroscope summarized b02e5cb.


Note

Medium Risk
New ZIP unpacking and IPC binary transfer paths are security-sensitive, though heavily capped; re-importing an existing VSIX collection replaces stored themes and can discard local edits after explicit confirmation.

Overview
Users can import color themes from a local .vsix extension package (paid or private themes), not only loose JSON or Open VSX search.

VSIX ZIP parsing, manifest handling, and theme extraction are moved into shared vsixThemePackage, and Open VSX import is rewired to use it so both paths stay aligned. Local imports use separate theme ids (vsix-theme-) and collection ids (local-vsix:), skip registry license/checksum checks, and still enforce the same archive size and safety limits.

Add a theme accepts one .vsix at a time via drag-and-drop or file picker; variants install as a single collection, with an update prompt when that collection is already installed (replacing variants and dropping local edits). On desktop, the native picker includes .vsix, reads up to 20 MB with a capped read, and returns binary data as optional contentBase64 on PickedThemeFile.

Reviewed by Cursor Bugbot for commit b02e5cb. Bugbot is set up for automated code reviews on this repo. Configure here.

A paid or private VS Code theme the user already owns has no import
path: the dialog only accepts loose JSON files, and Open VSX only
carries open-source extensions.

Extract the VSIX/ZIP machinery from openVsxThemes.ts into
vsixThemePackage.ts and reuse it for local files. A dropped or picked
.vsix imports every contributed color theme as one collection, so
re-importing the same extension offers an update instead of piling up
copies. Local packages skip the registry-only gates (license allowlist,
checksum) but keep every archive-safety limit. The desktop picker lists
.vsix and sends package bytes base64-encoded over IPC.
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 27, 2026
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3078f020-c379-42e9-8631-f0ebd65a1e24

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/desktop/src/ipc/methods/window.ts Outdated
A .vsix could grow between stat and readFile, pulling an arbitrarily
large archive into main-process memory before the renderer rejected it.
Read through a bounded loop that stops past the cap instead.
@ipanasenko
ipanasenko marked this pull request as ready for review August 27, 2026 17:02
@macroscopeapp

macroscopeapp Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a substantial local .vsix import workflow, including ZIP parsing, binary IPC transfer, persistent theme collections, and replacement of installed variants. Its new archive-processing and cross-process behavior extend beyond a small isolated change and warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant