Problem
pnpm dev runs three things concurrently on hardcoded ports — server on 7100, Vite on 7200, Electron pointing at 7200. If a stale pnpm dev instance is still running (easy to forget across terminals/IDE windows), a new one fails with a cryptic EADDRINUSE stack.
The packaged desktop build already grabs a random port via findFreePort() in packages/desktop/src/main.ts and the frontend doesn't need to know it (Hono serves the web bundle on the same origin in packaged mode, and Vite proxies /api in dev — either way React just calls relative /api/... URLs).
Proposal
Make Electron the dev orchestrator so dev mirrors packaged:
pnpm dev becomes pnpm --filter @github-dashboard/desktop dev (Electron is the only entry point).
- Electron main, in dev mode, picks two free ports, then spawns:
- the server as a child with
PORT=<srv>
- Vite as a child with
--port <web> and GHD_API_PORT=<srv>
packages/web/vite.config.ts reads GHD_API_PORT for server.proxy['/api'].target.
- Electron waits for both, then
loadURL("http://localhost:<web>").
Consequences
- No more port conflicts between concurrent
pnpm dev instances — each gets a fresh pair.
- Dev and packaged orchestration live in one file (
main.ts).
- The non-Electron browser dev workflow (point Chrome at
localhost:7200) goes away. Acceptable — the primary dev surface is the desktop app.
CLAUDE.md validation guidance needs updating (no more fixed 7100/7200 in dev).
Open questions
- Tooling like the Playwright MCP currently assumes
http://localhost:7200. We'd need a stable way to discover the current dev URL — e.g. write .logs/ports.json on startup.
Problem
pnpm devruns three things concurrently on hardcoded ports — server on 7100, Vite on 7200, Electron pointing at 7200. If a stalepnpm devinstance is still running (easy to forget across terminals/IDE windows), a new one fails with a crypticEADDRINUSEstack.The packaged desktop build already grabs a random port via
findFreePort()inpackages/desktop/src/main.tsand the frontend doesn't need to know it (Hono serves the web bundle on the same origin in packaged mode, and Vite proxies/apiin dev — either way React just calls relative/api/...URLs).Proposal
Make Electron the dev orchestrator so dev mirrors packaged:
pnpm devbecomespnpm --filter @github-dashboard/desktop dev(Electron is the only entry point).PORT=<srv>--port <web>andGHD_API_PORT=<srv>packages/web/vite.config.tsreadsGHD_API_PORTforserver.proxy['/api'].target.loadURL("http://localhost:<web>").Consequences
pnpm devinstances — each gets a fresh pair.main.ts).localhost:7200) goes away. Acceptable — the primary dev surface is the desktop app.CLAUDE.mdvalidation guidance needs updating (no more fixed 7100/7200 in dev).Open questions
http://localhost:7200. We'd need a stable way to discover the current dev URL — e.g. write.logs/ports.jsonon startup.