Skip to content

Windows: ship-ready build with repair and uninstall flows#16

Open
HKTITAN wants to merge 2 commits into
aronprins:masterfrom
HKTITAN:windows-support
Open

Windows: ship-ready build with repair and uninstall flows#16
HKTITAN wants to merge 2 commits into
aronprins:masterfrom
HKTITAN:windows-support

Conversation

@HKTITAN
Copy link
Copy Markdown

@HKTITAN HKTITAN commented May 5, 2026

Summary

Brings the existing dist:win pipeline up to ship quality on Windows and adds first-class repair, uninstall, and boot-failure diagnostics affordances. Verified end-to-end on Windows 11 — pnpm dist:win produces working NSIS + portable installers and the unpacked binary boots embedded Postgres + the UI on 127.0.0.1:3100.

This PR is two commits:

  1. feat(windows): production-ready Windows build with repair and uninstall flows — packaging hardening + Help-menu affordances
  2. fix(windows): extend boot timeout, add install pre-flight, surface server logs — runtime reliability + supportability

Changes

Windows runtime fixes (src/main.ts)

  • resolvePaperclipHome() now uses os.homedir() with USERPROFILE fallback. The previous process.env.HOME is empty on Windows, which broke the ~/.paperclip reuse check (it would join an empty string and end up checking a relative path).
  • resolveShellPath() short-circuits on win32 to avoid the unix $SHELL -lc 'echo $PATH' probe. Previously this just failed silently in the try/catch — now it's explicit.
  • findNodeBinary() uses R_OK instead of X_OK on Windows (where X_OK is just R_OK anyway), uses os.homedir() properly, and skips the NVM directory scan on win32.
  • startServer() spawns with windowsHide: true so the bundled node.exe no longer flashes a console window on every boot.
  • detached: !isWindows — never detached on Windows because there are no process groups there and orphaned postgres children would survive parent crashes.

Boot reliability + diagnostics

  • SERVER_STARTUP_TIMEOUT_MS: 60s → 300s. This was the single most common Windows install failure. On a clean Windows 11 machine with Defender enabled, embedded-postgres initdb + 75 schema migrations regularly takes 90–180s. The old 60s deadline timed out users in the middle of a successful boot.
  • validateServerEnvironment() pre-flight. Before spawning, we verify (a) the bundled node.exe exists and is readable, (b) the server bundle entrypoint exists, and (c) ~/.paperclip (or userData) is writable via a write-probe. Each failure produces a structured dialog that names the exact missing path and suggests a fix (antivirus quarantine, reinstall, OneDrive sync conflict, permissions).
  • tailInnerServerLog(). The bundled @paperclipai/server uses pino with a file destination, so almost nothing useful reaches the spawned child's stdout. We now poll-tail ~/.paperclip/instances/default/logs/server.log and feed lines into both the boot-progress UI and the error-dialog tail.
  • Better boot-failure dialogs. "Server failed to start in time" and "Server crashed during startup" now include the last ~2 KB of the inner pino log, the spawn paths, and the exact log file path, instead of the opaque "did not start in time" message.
  • Distinct progress steps. "Applying migrations..." appears as its own step so users on slow disks see real motion during the long initdb wait.

In-app repair / logs / uninstall

New Help menu entries:

  • Open Application Logs — opens %APPDATA%/Paperclip in Explorer.
  • Reset Local Data (Repair)… — confirms, stops the embedded server, wipes userData + ~/.paperclip, and relaunches the app.
  • Uninstall Paperclip… (Windows-only) — confirms, stops the server, hands off to the NSIS uninstaller next to the exe.

NSIS uninstaller polish (build/installer.nsh, electron-builder.yml)

  • Custom NSIS hook adds an "Also delete user data?" prompt covering %APPDATA%/Paperclip, %LOCALAPPDATA%/Paperclip, and %USERPROFILE%/.paperclip. Defaults to No and is suppressed during silent updater self-replace via ${isUpdated} so updates don't accidentally wipe data.
  • Desktop + Start-menu shortcuts enabled.
  • Stable artifact names: Paperclip-Desktop-Setup-${version}.exe and Paperclip-Desktop-Portable-${version}.exe (the prior Paperclip Desktop Setup 3.2.0.exe had spaces, which is awkward for download URLs and CI scripts).
  • differentialPackage: true for delta updates on the NSIS channel.

Documentation

  • docs/prds/windows-release.md — converted the Open Questions section into a Resolved Decisions subsection that records what the PR actually shipped (portable alongside NSIS, per-user install, bundled-node-only runtime, opt-in ~/.paperclip reuse, repair/uninstall affordances). Slimmer remaining Open Questions list now focuses on signing, EV vs OV, and MSI/Store.
  • docs/development/windows-troubleshooting.md (new) — support-oriented guide covering log locations, the repair and uninstall flows, and a table mapping each pre-flight error dialog title to its likely cause and fix.

Build hygiene

  • package.json declares pnpm.onlyBuiltDependencies for @embedded-postgres/windows-x64, electron, and sharp. Under pnpm 10 their postinstall scripts are blocked by default; this whitelists them so pnpm install produces a working tree without manual pnpm approve-builds.
  • .gitignore ignores build/ui-staging/ (scratch dir created by build-ui.mjs while @paperclipai/ui isn't on npm).

Auto-update

Already wired via electron-updater and publish: github in electron-builder.yml; no changes needed. The artifact-name change keeps latest.yml in the same path, so existing update channels keep working once a Windows release is cut. The portable channel is intentionally update-free.

Test plan

  • pnpm test:connections — 29/29 pass on Windows
  • pnpm build — clean (tsc strict mode)
  • pnpm dist:win — produces NSIS installer (~179 MB) + portable (~178 MB) + latest.yml + .blockmap
  • Launched unpacked binary on Windows 11: embedded Postgres 18.1 starts on port 54329, all 75 migrations apply, server listens on 127.0.0.1:3100, UI assets serve 200
  • Verified findNodeBinary() resolves the bundled node-bin/node.exe and extraResources packs the win-x64 server bundle correctly
  • Verified pre-flight failure paths: deleted node.exe → "Bundled Node.js runtime is missing" dialog with correct path; chmod-removed write on %USERPROFILE%\.paperclip → "Local data directory is not writable" dialog
  • Verified repair flow: Help → Reset Local Data confirms, stops postgres, wipes data, relaunches successfully
  • Verified uninstall flow: Help → Uninstall Paperclip shows confirm, then NSIS prompts for "also delete user data" and respects the choice
  • Code-signing not exercised (no Windows cert available in this environment) — the existing release.yml workflow only needs the Azure Artifact Signing secrets documented in docs/development/windows-signing-guide.md to start producing signed builds

Notes

  • macOS / Linux behavior is untouched. All Windows-specific branches gate on process.platform === "win32" and the existing tests still pass.
  • The repository's existing release.yml workflow already has a build-windows job — this PR makes the artifacts it produces ready to ship.

HKTITAN and others added 2 commits May 5, 2026 11:43
…ll flows

Brings the existing dist:win pipeline up to ship quality on Windows and
adds first-class repair / uninstall affordances:

- main.ts: use os.homedir() with USERPROFILE fallback in
  resolvePaperclipHome() so the ~/.paperclip reuse check works on Windows
  (process.env.HOME is empty there).
- main.ts: short-circuit resolveShellPath() on win32 to avoid the unix
  shell -lc 'echo $PATH' probe (no behavior change, less log noise).
- main.ts: Help menu gains "Open Application Logs",
  "Reset Local Data (Repair)..." and (Windows-only)
  "Uninstall Paperclip..." entries that confirm, kill the embedded
  server, wipe user data and either relaunch or hand off to the NSIS
  uninstaller.
- electron-builder.yml: NSIS receives a custom include with an
  "also delete user data" prompt covering %APPDATA%/Paperclip,
  %LOCALAPPDATA%/Paperclip and %USERPROFILE%/.paperclip; suppressed
  during silent updater runs via ${isUpdated}. Adds desktop +
  start-menu shortcuts, stable Paperclip-Desktop-Setup-* /
  Paperclip-Desktop-Portable-* artifact names, and
  differentialPackage for delta updates.
- package.json: declare pnpm.onlyBuiltDependencies so
  @embedded-postgres/windows-x64, electron and sharp run their
  postinstall scripts under pnpm 10.
- .gitignore: ignore build/ui-staging/ scratch dir produced by
  build-ui.mjs when @paperclipai/ui isn't on npm.

Verified end-to-end on Windows 11: pnpm dist:win produces signed-eligible
NSIS + portable installers (~179MB), the unpacked binary boots embedded
Postgres 18.1, applies all 75 migrations, listens on 127.0.0.1:3100, and
serves the UI. All 29 connection tests pass.
…rver logs

The most common Windows install failure was 'Server did not start within
60000ms' but on a clean Windows machine with antivirus scanning every
binary, embedded-postgres initdb + 75 migrations regularly takes 90-180s.
The error dialog also gave the user no actionable information.

This commit fixes both:

- SERVER_STARTUP_TIMEOUT_MS: 60s -> 300s. Covers cold-start + initdb +
  full migration run on Windows 11 with Defender enabled.
- validateServerEnvironment(): pre-flight check for the bundled node.exe,
  the server bundle entrypoint, and write access to ~/.paperclip. Each
  failure produces a structured dialog that names the missing path and
  suggests a remediation (antivirus, reinstall, permissions/OneDrive).
- tailInnerServerLog(): the bundled @paperclipai/server uses pino with a
  file destination so its real boot progress and crash traces never hit
  stdout. We now tail
  ~/.paperclip/instances/default/logs/server.log
  and feed lines into the same boot-progress UI + the error dialog tail.
- 'Server failed to start' / 'Server crashed during startup' dialogs now
  include the last 2KB of that log instead of 'did not start in time'.
- findNodeBinary(): use R_OK instead of X_OK on Windows (X_OK is just
  R_OK there); fall back to os.homedir() instead of process.env.HOME;
  skip the NVM scan on Windows.
- windowsHide: true on spawn so the bundled node.exe doesn't flash a
  console window on every boot.
- Distinct 'Applying migrations...' progress step so users on slow
  disks see motion during the long initdb wait.

Also refreshes docs/prds/windows-release.md to record the Open Questions
this PR resolved (portable shipped alongside NSIS, per-user install,
bundled-node-only runtime, opt-in ~/.paperclip reuse) and adds a new
docs/development/windows-troubleshooting.md mapping each pre-flight
dialog title to its likely cause and fix.

No behavior change on macOS or Linux.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant