# bring back electron \(\+ websocket/package changes\) \(\#10\) · screen/t3code-personal

[View on GitCafe](https://git.cafe/screen/t3code-personal/commit/8ebd2479cf976a6ef79843b97d477777efb7cb6a)

Repository: [screen/t3code-personal](https://git.cafe/screen/t3code-personal)

Visibility: public

Requested revision: 8ebd2479cf976a6ef79843b97d477777efb7cb6a

Requested commit: 8ebd2479cf976a6ef79843b97d477777efb7cb6a

Commit: 8ebd2479cf976a6ef79843b97d477777efb7cb6a

Tree: 85e8cea2dc57ab2e1c59cc74576ff027c37464d0

Author: Theo Browne

Committer: GitHub

## Message

```
bring back electron (+ websocket/package changes) (#10)

* feat: scaffold apps/server package and WebSocket protocol types

- Create apps/server with package.json, tsconfig, tsup config
- Copy codexAppServerManager, providerManager, fixPath from desktop (no Electron deps)
- Add WebSocket message protocol schemas (WsRequest, WsResponse, WsPush) to @acme/contracts
- Define WS_METHODS and WS_CHANNELS constants for type-safe routing

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: implement WebSocket + HTTP server and CLI entry point

- wsServer.ts: WebSocket server routes NativeApi methods, serves static files
  - Provider events pushed to all connected clients
  - SPA fallback for client-side routing
  - Server welcome message with cwd/projectName on connect
- index.ts: CLI entry point
  - Auto-detects available port (default 3773)
  - Resolves renderer dist for static serving
  - Opens browser on startup via 'open' package
  - Graceful shutdown on SIGINT/SIGTERM

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: WebSocket transport and NativeApi implementation for browser

- wsTransport.ts: WebSocket client with request/response, push subscriptions,
  auto-reconnect with exponential backoff
- wsNativeApi.ts: Full NativeApi implementation over WebSocket transport
  - All provider methods routed through WS_METHODS
  - Provider events streamed via WS_CHANNELS.providerEvent
  - Todos/terminal/agent stubbed (not needed for web mode)
  - dialogs.pickFolder returns null (text input fallback in UI)
- session-logic.ts: readNativeApi() now auto-detects environment
  - Prefers Electron preload bridge if available (window.nativeApi)
  - Falls back to WebSocket transport for browser mode
- onServerWelcome() hook for renderer to receive cwd on connect

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: adapt renderer for browser mode

- App.tsx: Add AutoProjectBootstrap that listens for server welcome
  and auto-creates project + thread from server's cwd
- Sidebar: Conditionalize drag region (Electron only), hide Browse button in browser
- ChatView: Conditionalize drag region, adjust padding for browser
- DiffPanel: Same drag region treatment
- index.html: Update title to 'CodeThing'
- env.ts: isElectron detection utility

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: monorepo & CLI integration

- Root package.json: Add dev, dev:server, dev:web, start scripts
  - dev runs both server and renderer in parallel via turbo
  - VITE_WS_URL injected so renderer connects to server in dev mode
- turbo.json: Add WS env vars to globalEnv
- vite.config.ts: Inject VITE_WS_URL at build time for WS server discovery
- wsTransport.ts: Use VITE_WS_URL env var in dev, fall back to page URL in prod
- Server dev script: Uses tsx for direct TypeScript execution with VITE_DEV_SERVER_URL

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: remove Electron desktop app, clean up contracts and docs

- Delete apps/desktop/ entirely (replaced by apps/server)
- Remove IPC_CHANNELS constant from contracts (no longer needed)
- Keep NativeApi interface (still the renderer's API contract)
- Keep EDITORS constant (used by both server and renderer)
- Update README.md with new architecture diagram and scripts
- Update AGENTS.md with new package roles and architecture

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* test: add WebSocket server integration tests

- Tests welcome message on connect with cwd/projectName
- Tests server.getConfig method
- Tests providers.listSessions returns empty array
- Tests error response for unknown methods
- Tests graceful handling of invalid JSON
- All 73 tests pass across 12 test files

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* fix: address lint warnings in new files

- wsTransport.ts: Use addEventListener instead of on-function assignments
- wsServer.ts: Replace filter(Boolean).pop() with direct array access
- wsServer.test.ts: Use addEventListener for WebSocket events

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* fix: race condition in auto-project bootstrap + cleanup

- wsNativeApi: Cache last welcome payload and replay to late subscribers.
  Fixes race where WS connect + welcome arrives before React effect fires.
- App.tsx: Add bootstrappedRef to prevent duplicate project creation,
  skip bootstrap in Electron mode
- wsTransport: Use standard import.meta.env for VITE_WS_URL access
- CLAUDE.md: Fix header (was incorrectly '# AGENTS.md')

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* fix: use tsx command directly in server dev script

Use 'tsx src/index.ts' instead of 'node --import tsx' for simpler dev execution

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* chore: clean up stale Electron references and config

- Remove smoke-test script (was desktop-only)
- Remove dist-electron from turbo outputs and .gitignore
- Rename ELECTRON_RENDERER_PORT → PORT in vite.config.ts
- Clean up turbo globalEnv (remove ELECTRON_RENDERER_PORT, WS_SERVER_PORT)
- Update CI workflow to use bun 1.3.9 (matches package.json engines)

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* feat: make t3 package publishable for npx

- Remove private:true so package can be published to npm
- Add files field to limit published files to dist/
- Move @acme/contracts to devDependencies (bundled by tsup)
- Add @acme/renderer devDependency for turbo build ordering
- Add bundle-client.mjs: copies renderer build into dist/client/
- Update resolveStaticDir to check dist/client/ first (npx scenario),
  then fall back to monorepo layout (../../renderer/dist)
- Full build pipeline: contracts → renderer → server + bundle client

Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>

* fix tests

* turborepo and better logging

* bring back electron

* fix

* Promise catching fixes

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>
```

## Parents

- [e7c4292d271f14ace547c135089245825b82e17b](https://git.cafe/screen/t3code-personal/commit/e7c4292d271f14ace547c135089245825b82e17b?format=markdown)

[Source at this commit](https://git.cafe/screen/t3code-personal/tree/8ebd2479cf976a6ef79843b97d477777efb7cb6a?format=markdown)
