Skip to content

Shrink the Windows MSI to runtime files - #92

Merged
leoisadev1 merged 13 commits into
mainfrom
cursor/windows-msi-size-8c4c
Oct 8, 2026
Merged

leoisadev1 merged 13 commits into
mainfrom
cursor/windows-msi-size-8c4c

Conversation

@leoisadev1

@leoisadev1 leoisadev1 commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Public feedback on X: the Windows MSI is about 500 MB while the Mac and Linux downloads are about 50 MB. That is almost all packaging, not the app.

What was in the v0.2.0 MSI (537 MiB)

Extracted with 7-Zip from convt-0.2.0-windows-x86_64.msi. The cabinets already use LZX:18 (high compression). The File table uses hashed names; sizes and magic identify the members.

Cabinet Compressed Uncompressed What it is
cab2 443.8 MiB 445.8 MiB documents.tar.gz — the optional LibreOffice pack, already gzipped so CAB barely helps
cab3 61.2 MiB 194.1 MiB ffmpeg.exe (97.2 MiB) and ffprobe.exe (97.0 MiB), Gyan essentials static
cab1 18.0 MiB 57.7 MiB convt-app.exe (35.7 MiB), convt.exe (15.0 MiB), aom.dll, CRT, LICENSE.txt
cab4 13.3 MiB 67.5 MiB 2,316 files: codec source trees under licenses/native-source/ plus the remaining runtime DLLs (heif.dll, libde265, x265, pdfium, more CRT)
MSI 537 MiB Mac DMG 47.7 MiB, Linux AppImage 55.8 MiB

WiX harvested packaging/out/windows/payload/**. That directory held the document pack (product docs already call this a separate opt-in on Mac and Linux) and the full x265 / libde265 / aom / libheif source trees.

No PDBs and no uncompressed CAB. The leftover bulk after this fix is the two static FFmpeg binaries (~61 MiB compressed), which the app needs at runtime. Expected MSI after the change: about 80–90 MiB (cab1 + cab3 + the runtime DLLs from cab4). CI fails the job if the MSI is 120 MiB or larger.

How document support works

Mac and Linux already download the LibreOffice pack on demand. Selecting a Word/Excel/PowerPoint file shows Quick convert's Download card; nothing hits the network until the user clicks Install (or runs convt pack install documents). The engines then fetch CONVT_DOCUMENT_PACK_URL, verify the compiled SHA-256, and install under the per-user data directory. A silent convert never downloads.

Those platforms do not ship the pack inside the AppImage/DMG, and they do not yet publish a hosted archive, so a released Mac/Linux build only converts documents if LibreOffice is already on the machine.

Windows used to embed the 446 MiB pack in the MSI (bundle:documents.tar.gz) so Install worked offline. That is what made the installer 537 MiB. Windows now matches the Mac/Linux installer code:

  • The MSI stays runtime-only.
  • The Windows job publishes convt-<version>-windows-x86_64-documents.tar.gz and .sha256 on the same windows-release-review artifact (and then on the GitHub release).
  • The app is compiled with CONVT_DOCUMENT_PACK_URL pointing at that release asset, plus the digest and sizes. Quick convert shows the existing Download card (size, progress, checksum failure, retry). convt pack install documents fetches and verifies it.

The website update manifest does not list the pack as a Windows app download. Only the compiled URL fetches it.

What changed

  • build.ps1 writes the pack beside the payload, names it convt-<version>-windows-x86_64-documents.tar.gz, writes the checksum, and compiles the GitHub release URL.
  • build-native.ps1 copies codec LICENSE/COPYING/NOTICE files only, not the source trees.
  • stage_payload.py is the harvest allowlist: executables, DLLs, and notices. It refuses the document pack, native-source, PDBs, .lib files, and headers.
  • assemble.py requires the pack and checksum whenever the Windows MSI is included.
  • WiX MediaTemplate sets CompressionLevel="high". MSI artifact name stays windows-release-review / convt-<version>-windows-x86_64.msi.
  • release-windows.yml still runs on windows-latest. After packaging, smoke.ps1 extracts the MSI, converts a PNG and an MP4, installs the sibling document pack, converts a Word file to PDF, and fails if convt-app.exe exits or does not start.
  • installer.ps1 retries by removing only the owned msi-payload harvest directory.
  • Changeset on @convt/desktop (and the fixed CLI/web group) so this ships in the next release.

PR #73 is also editing release CI. This only adds the smoke step, the extra Windows review files, a short release-notes line, and unit tests on the existing ubuntu-24.04 release-scripts job. Runners are unchanged.

Proof so far

  • python3 -m unittest discover -s packaging/windows (payload allowlist, document-pack URL/checksum, smoke script contract).
  • python3 -m unittest discover -s scripts/release (assemble now requires the Windows pack and checksum).
  • App UI for Download / progress / checksum already has tests in crates/convt-app/src/ui/tests.rs (a_build_without_a_pinned_pack_offers_no_download vs the configured Download card).

How to dry-run the real MSI

A reviewer can:

  1. Actions → Build release windows → Run workflow.
  2. Use branch cursor/windows-msi-size-8c4c.
  3. Inputs: version=0.2.0 (must match this commit), source_date_epoch = any UTC unix time (for example 1791331200), dry_run=true.
  4. The job uploads windows-release-review: the MSI, convt-0.2.0-windows-x86_64-documents.tar.gz, and .sha256.
  5. The Smoke-test the extracted MSI step prints the MSI byte size, converts a PNG and an MP4, installs the document pack from that archive, converts a Word file to PDF, and fails if convt-app.exe does not stay running. The job fails if the MSI is 120 MiB or larger.

Do not merge; a reviewer will merge it.

Open in Web Open in Cursor 

Devin Review

The v0.2.0 MSI was 537 MiB because WiX harvested the optional
LibreOffice documents.tar.gz and the codec source trees. Stage only
the executables, DLLs and notices, use high CAB compression, and
smoke-test an extracted image and video conversion.

Co-authored-by: Leo <leoisadev1@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread packaging/windows/stage_payload.py Outdated
Comment on lines +85 to +88
names = {path.name for path in files}
for required in REQUIRED:
if required not in names:
errors.append(f"missing required runtime file: {required}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Missing runtime files pass staging

When convt.exe is missing from the payload root, validate accepts a namesake under licenses. stage leaves that namesake under licenses, so the MSI lacks its CLI.

Suggested change
names = {path.name for path in files}
for required in REQUIRED:
if required not in names:
errors.append(f"missing required runtime file: {required}")
names = {path.name for path in files if path.parent == root}
for required in REQUIRED:
if required not in names:
errors.append(f"missing required runtime file: {required}")

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

$env:CONVT_LICENSE_STORE = 'file'
$env:CONVT_CONFIG_DIR = Join-Path $Work 'cfg'
$env:CONVT_DATA_DIR = Join-Path $Work 'data'
$env:CONVT_PDFIUM_DIR = $Bin

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 PDFium discovery remains untested

Setting CONVT_PDFIUM_DIR bypasses normal PDFium discovery. The smoke test also skips PDF conversion, so it cannot validate PDF support in an ordinary install.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

cursoragent and others added 2 commits October 7, 2026 21:28
Mac and Linux already download document support after Install; they
just have no hosted archive yet. Windows now compiles that same URL
against convt-<version>-windows-x86_64-documents.tar.gz on the GitHub
release and verifies the pinned checksum. The MSI stays runtime-only.

Co-authored-by: Leo <leoisadev1@users.noreply.github.com>
Staging treated a namesake under licenses as convt.exe. Required
files must sit at the payload root. Smoke now checks the compiled
GitHub release URL against the published checksum, and assemble
refuses a pack without its .sha256.

Co-authored-by: Leo <leoisadev1@users.noreply.github.com>
@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High risk] Restructures Windows installer build and packaging.

The PR appears safe to merge; both numbered previous findings are fixed and no new blocking issue was found.

What we checked:

  • Rebuilds use the current URL: publish() now derives the URL from the current version rather than the environment. The build restores the caller’s URL after compilation.
  • Smoke runs use separate folders: Each run gets a new GUID for its extraction, work, and profile folders. Cleanup uses those run-specific paths.

Summary

The Windows MSI now contains runtime files and notices instead of the document pack and codec source trees.

  • The document pack and checksum are published beside the MSI.
  • Packaging and smoke checks enforce the 120 MiB limit.
  • The latest changes fix stale build URLs and shared smoke folders.
  • No new actionable issues were found. The Windows MSI and smoke run were not executed in this Linux environment.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  Build[Windows build] --> Runtime[Executables, DLLs and notices]
  Runtime --> Stage[Runtime-only harvest]
  Stage --> MSI[Windows MSI]
  Build --> Pack[Versioned document pack and checksum]
  Pack --> Release[GitHub release assets]
  Build --> Pin[Compile release URL and digest]
  Release --> Install[User clicks Install]
  Pin --> Install
  Install --> Verify[Verify digest before installing]
Loading

Reviews (7) · Last reviewed commit: "fix(windows): isolate smoke dirs and sto..." · Reviewed by Greptile

Comment thread packaging/windows/smoke.ps1 Outdated
Comment thread packaging/windows/stage_payload.py Outdated
Comment thread packaging/windows/installer.ps1 Outdated
cursoragent and others added 9 commits October 7, 2026 21:42
FFmpeg's color source is 25 fps, so d=0.1 produced several frames and
the image2 muxer refused sample.png. That failed the required smoke
step before the MSI and document pack uploaded. Also keep COPYING.LESSER
and LICENSE-1 notices, and restage msi-payload so a WiX retry works.

Co-authored-by: Leo <leoisadev1@users.noreply.github.com>
Install the sibling document pack, convert a Word fixture to PDF, and
fail if convt-app.exe exits. Retry cleanup now removes only the owned
msi-payload harvest directory.
pwsh parsed $ExpectedStage: as a variable and failed the MSI package
step before smoke could run.
Staging refused licenses/pdfium/libjpeg_turbo.ijg, which blocked the
unsigned MSI. Keep every non-source file under licenses/.
The runner workspace is on D:\, and pack discovery rejects that volume
root. Use the per-user profile, then convert the Word fixture to PDF.
Keep the MSI smoke (document pack install, DOCX to PDF, GUI stay-running) and the PE subsystem checks from main.
Comment thread packaging/windows/document_pack.py Outdated
Comment thread packaging/windows/smoke.ps1 Outdated
Give each smoke run unique LOCALAPPDATA and extract folders, and compile the versioned GitHub pack URL even when a previous build left CONVT_DOCUMENT_PACK_URL set.
@leoisadev1
leoisadev1 merged commit 9214ba0 into main Oct 8, 2026
11 checks passed
@leoisadev1
leoisadev1 deleted the cursor/windows-msi-size-8c4c branch October 8, 2026 01:46
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