Skip to content

feat(desktop): add Windows desktop build support - #115

Merged
bholmesdev merged 6 commits into
bholmesdev:mainfrom
saucy-tech:feat/windows-desktop-build
Jun 27, 2026
Merged

feat(desktop): add Windows desktop build support#115
bholmesdev merged 6 commits into
bholmesdev:mainfrom
saucy-tech:feat/windows-desktop-build

Conversation

@saucy-tech

Copy link
Copy Markdown
Contributor

Description

Adds Windows desktop build support, completing the macOS → Linux (#100) → Windows desktop lineage.

Closes #114

What's included:

  • electron-builder Windows NSIS target + nsis config in apps/desktop/package.json, plus bundle:win / bundle:desktop:win scripts that mirror the existing mac/linux ones.
  • A release-windows job in desktop-release.yml so tagged desktop-v* releases publish a Windows .exe alongside the mac/linux artifacts (with shell: bash on the version-check/build steps for windows-latest).
  • Fix: resolvePath now normalizes POSIX-style Windows asset paths (/C:/…). Without this, path.resolve produced C:\C:\…, which failed the granted-scope check, so the hubble-asset:// protocol served nothing — HTML Apps rendered blank and local Markdown images failed on Windows. macOS/Linux are unaffected (guarded on process.platform === "win32").
  • .gitattributes (* text=auto eol=lf) so a Windows clone (core.autocrlf=true) doesn't check out CRLF and fail pnpm check (Biome) on ~200 files. Verified near-no-op: git add --renormalize . changed 0 files (all tracked files are already LF).
  • README / desktop README / CHANGELOG.md updated.

Native non-mac window controls already landed in #100, so no renderer/title-bar changes are needed here.

History note: the desktop app moved from Tauri to Electron in June 2026, so #19's earlier (Tauri-based) closure no longer reflects the codebase — this adds real Electron/NSIS Windows support.

Why NSIS (not Squirrel): custom install directory, no update-feed dependency, and it matches the current macOS-only auto-update model (Windows users update by reinstalling).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Documentation update

Testing

  • Existing tests pass
  • Added new tests for changes
  • Tested manually (describe below)

Manual Testing Details:

Built and tested on Windows 11 (Node 22, pnpm 10):

  • pnpm build (Biome + build-all + typecheck) and pnpm test both green.
  • pnpm bundle:desktop:win produced hubble_0.1.14_x64.exe (NSIS); installed and launched.
  • Verified in the running app: sidebar tree + nested folders, open/edit/save to disk, both sample HTML Apps (file-index.html, todo-demo.html) reading workspace files, and local Markdown images — all working after the resolvePath fix.

The asset-path fix is verified via the running app (screenshots below); the Electron main process isn't currently unit-tested in this repo, so I matched that convention — happy to add a focused test if you'd prefer.

Screenshots (Windows 11)

Markdown editor — rich rendering + local image

Markdown editor on Windows

HTML App — workspace file index (reads **/*.md via the file broker)

file-index HTML App on Windows

HTML App — todo board (reads frontmatter from todos/)

todo-demo HTML App on Windows

Checklist

Adds Windows packaging for the Electron desktop app, matching the
existing macOS and Linux targets:

- electron-builder `win` target (NSIS installer) + `nsis` config in
  apps/desktop/package.json, with `bundle:win` / `bundle:desktop:win`
  scripts mirroring the mac/linux ones
- `release-windows` job in the Desktop Release workflow so tagged
  releases publish a Windows installer alongside macOS and Linux
- `.gitattributes` enforcing LF so Windows clones (core.autocrlf=true)
  don't fail `pnpm check` on CRLF line endings
- README / desktop README updated to reflect Windows support

Native window controls on Windows already landed with Linux support
(bholmesdev#100), so no renderer changes are needed.
HTML Apps use forward-slash asset URLs as their base, and workspace
file paths flow through the renderer as POSIX-style strings. On Windows
these arrive at the main process as "/C:/notes/..." with a leading
slash before the drive letter. path.resolve treats that as
drive-relative and prepends the current drive ("C:\C:\notes\..."),
which fails the granted-scope check, so the hubble-asset:// protocol
served nothing: HTML Apps rendered blank and local images 404'd.

Normalize the leading slash before a drive letter in resolvePath so
these paths resolve to a real Windows path. macOS/Linux are unaffected
(guarded on process.platform === "win32").
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

@saucy-tech is attempting to deploy a commit to the bholmesdev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@saucy-tech

Copy link
Copy Markdown
Contributor Author

Draft for reference, happy to discuss the approach or hold/adjust.

@bholmesdev

Copy link
Copy Markdown
Owner

Fantastic, thanks for opening this! I'll test on a Windows install later tonight.

@bholmesdev

Copy link
Copy Markdown
Owner

Noticed in the screenshots that the window controls aren't visible in the top right. Is that just a limitation of your screenshot tool, or do we still need to render those?

@saucy-tech

saucy-tech commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Oh yes windows controls are present, used chrome dev tools on those screenshots earlier. image
Screenshot 2026-06-26 111055
Screenshot 2026-06-26 111112

@saucy-tech

saucy-tech commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Heads up before you test. I did more testing today and hit a couple of pre-existing Windows path bugs (not from this PR's changes, but worth fixing here since it's about Windows working):

  • New file / new folder and Reveal in File Explorer fail. Root cause: the workspace path is held with backslashes (C:\Scratch) while file/folder paths use forward slashes (C:/Scratch/...), so the sidebar's path helpers join them into a doubled path — e.g. Path is outside granted scope: C:\Scratch/C:/Scratch/new-file.md. It's also why the sidebar shows C:\Scratch (header) and C:/Scratch (tree) as two entries.

I'm fixing it by normalizing paths to forward slashes and will push to this PR with Windows test evidence (new file/folder at root + nested, rename, reveal, etc.).

The renderer builds paths with forward slashes, but the main process
returned native paths (backslash on Windows) from the directory
listing, launch workspace path, folder/file pickers, watch events, and
open-file events. The mix broke the sidebar's path helpers: relative-
path stripping failed, so the workspace root and folders became phantom
nested nodes (C: > Scratch > ...) and folder ids fed back into absolute-
path joins produced doubled paths like "C:\ws/C:/ws/new-file.md" —
breaking New file, New folder, and Reveal in File Explorer, and showing
the workspace twice in the sidebar.

Add toRendererPath() and apply it at every main->renderer path boundary
so the renderer always sees forward slashes (collectWorkspaceFiles and
the image-paste path already did this). resolvePath already normalizes
them coming back. macOS/Linux are unaffected (path.sep is already "/").
@saucy-tech

Copy link
Copy Markdown
Contributor Author

Pushed the fix for the Windows path bugs from the heads-up above.

Root cause: the main process returned native (backslash) paths for the directory listing, launch workspace path, folder/file pickers, watch events, and open-file events, while the renderer builds forward-slash paths. The mismatch broke the sidebar's relative/absolute path helpers — the workspace root turned into a phantom C:/Scratch node and folder ids got re-joined into doubled paths (C:\Scratch/C:/Scratch/new-file.md), which broke New file / New folder / Reveal and showed the workspace twice in the sidebar.

Fix: a small toRendererPath() helper applied at every main→renderer path boundary so the renderer always receives forward slashes (matching what collectWorkspaceFiles and the image-paste path already did). resolvePath already normalizes them on the way back, so writes/grants resolve to native paths. macOS/Linux are unaffected (path.sep is already /).

Verified on Windows 11 after the fix:

  • New file at root ✓, new file in a subfolder ✓, new folder ✓
  • Sidebar no longer shows the duplicate C:\Scratch / C:/Scratch
  • Reveal in File Explorer resolves correctly now ✓
  • Regression: open/edit/save, HTML Apps, and local images all still render ✓
  • pnpm build (Biome + typecheck) and pnpm test green

Rename is covered by the existing renames to nested paths in Windows workspaces test (it exercises backslash workspace paths). Happy to squash these path fixes into the main commit before you merge if you'd prefer.

@bholmesdev

Copy link
Copy Markdown
Owner

This is a great PR. Spent some time setting up a virtual machine on my Mac to run this on Windows. It exposed a couple other setup problems when using Windows on ARM64, so I committed some patches for that.

I'm also tracking a separate issue #118 to pin the package manager and allowBuilds so that installation works with pnpm the first time.

This feels good to merge to start getting Windows releases out there. Thanks for doing this!

@bholmesdev
bholmesdev marked this pull request as ready for review June 27, 2026 03:54
@bholmesdev
bholmesdev merged commit a4efa8f into bholmesdev:main Jun 27, 2026
6 checks passed
@saucy-tech
saucy-tech deleted the feat/windows-desktop-build branch June 27, 2026 09:53
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.

Windows desktop builds (NSIS installer)

2 participants