feat(electron): launch-connection chooser + Windows native build#377
Conversation
Adds an Electron launch-connection chooser window that discovers and probes running Freshell servers via an unauthenticated /api/health endpoint (now reporting instanceId/startedAt/requiresAuth), with token resolution and an always-ask/one-time launch policy. Also adds the native-Windows NSIS build pipeline (electron:build:win) that compiles node-pty for win32 and bundles a standalone Node runtime. - electron: launch-chooser window + discovery/policy/token-resolver, IPC handlers (get/choose-launch-option), tray icon path helper - server: extract /api/health into createHealthRouter with launch discovery metadata (instanceId, startedAt, requiresAuth) - build: electron:build:win + assert-native-windows-build guard, installer.nsh (NSIS one-click), bundled-node prep (tar/extract-zip), build:launch-chooser vite config - docs: docs/development/windows-electron-build.md + AGENTS.md pointer - tests: unit coverage for chooser logic, discovery, policy, token resolver, icon path, health router, build guard, electron-builder config, prepare-bundled-node; e2e-electron smoke Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 56e21ca556
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| } | ||
|
|
||
| await options.patchDesktopConfig({ |
There was a problem hiding this comment.
Honor the unchecked Remember choice
When the chooser sends remember: false (the user unchecked “Remember this choice”), this handler still unconditionally writes the selected serverMode, remoteUrl, and remoteToken to desktop.json; the start-local branch likewise persists the local mode. As a result, a one-time connection is saved and can auto-connect on the next launch, and remote tokens are stored despite the user's explicit choice. Gate the config patch on choice.remember or use a transient startup path for one-time launches.
Useful? React with 👍 / 👎.
| await chooser.waitForLoadState('domcontentloaded') | ||
|
|
||
| await chooser.getByRole('checkbox', { name: 'Always ask on launch' }).uncheck() | ||
| await chooser.getByRole('button', { name: 'Connect', exact: true }).first().click() |
There was a problem hiding this comment.
Query the chooser button by its accessible name
In this flow, the candidate button rendered by LaunchChooser has an aria-label like Connect to localhost:3001, and ARIA labels override the visible text for role queries. With exact: true, this locator looks for the accessible name Connect, so the new e2e fails before it can exercise connecting from the chooser; query the actual accessible name or avoid the exact visible-text match.
Useful? React with 👍 / 👎.
The launch-chooser/Windows-build tests assumed POSIX path separators and LF line endings, so they failed on the windows-latest CI runner (this feature's first run on Windows): - startup + prepare-bundled-node: assert against path.join() output (OS-native separators) instead of hardcoded '/', and normalize separators where only path structure matters - electron-builder-config: normalize CRLF -> LF before regex/content assertions (a Windows checkout may convert the LF repo files) Production code is unchanged; path.join output is correct on each host. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Lands the Electron launch-connection chooser plus the native-Windows build pipeline (the source behind the Windows installer).
/api/health(createHealthRouter) reportinginstanceId/startedAt/requiresAuth, plus token resolution and an always-ask / one-time launch policy.npm run electron:build:win, guarded byassert-native-windows-build(must run on win32 sonode-ptycompiles native), producing a one-click NSIS installer (installer.nsh) with a bundled standalone Node runtime and a dedicated launch-chooser Vite bundle.docs/development/windows-electron-build.md(how to build on native Windows, including the WSL-via-interop recipe) + anAGENTS.mdpointer.Notes
Reconstructed cleanly on top of current
origin/main. The original working branch was a stale May-24 tree that also carried work since merged separately (favicon #363, codex runtime-flake #376); that is intentionally not included here.server/index.tsandpackage.jsonwere 3-way merged so upstream's claude-activity wiring andrun-with-default-portdev scripts are preserved.Test plan
npm run typecheck,npm run build:electron,npm run build:launch-chooser— greennpm test) — green (incl. new unit coverage for chooser logic/UI, discovery, launch policy, token resolver, icon path, health router, build guard, electron-builder config, prepare-bundled-node)node.exe+ win32node-pty+ packaged launch-chooser)🤖 Generated with Claude Code