Skip to content

feat: mobile UI scaffold + desktop build wiring + dev port scheme (17687/5179) - #1

Merged
johnnyhuy merged 2 commits into
mainfrom
feat/mobile-ui-desktop-build
Jul 17, 2026
Merged

feat: mobile UI scaffold + desktop build wiring + dev port scheme (17687/5179)#1
johnnyhuy merged 2 commits into
mainfrom
feat/mobile-ui-desktop-build

Conversation

@johnnyhuy

Copy link
Copy Markdown
Contributor

Summary

Two commits covering the mobile UI MVP, the desktop-shell build gap,
and a port scheme that gets the dev loop off Paseo / Vite / Metro defaults.

Mobile UI scaffold (feat(app): scaffold mobile UI for connect/sessions/transcript)

Three screens on top of @echohello/client:

  • connect — manual ws:// endpoint + label, persists to AsyncStorage,
    drives SupaplaneClient.connect()
  • sessions — workspace list grouped by freshness, tap to drill in
  • session/[id] — transcript + composer (send / abort / start)
    bound to ClientCommand wire types

Shared infra:

  • zustand connection-store owns a single SupaplaneClient instance,
    status, workspaces, sessions, and a per-session event buffer
  • AsyncStorage v3 wrapper (setMany / removeMany) for the saved
    endpoint and TOFU-pinned server fingerprint
  • Dark theme tokens, Button, TextField, ConnectionBanner

Bundler plumbing: metro.config.cjs declares explicit
watchFolders and nodeModulesPaths so Bun's hoisting doesn't trip
Metro when resolving app/ screens from a monorepo root.

Desktop build wiring + dev port scheme (chore(dev): wire desktop build + shift dev ports off 6767/5173)

The existing desktop/dev: electron . was broken — Electron's Node
couldn't load TS or follow .js import paths into .ts sources.
Now:

  • packages/desktop/tsconfig.build.json emits ESM to dist/
  • packages/desktop/package.jsondev runs tsc then electron
  • @echohello/server and @echohello/protocolexports point at
    dist/ so Electron's Node can resolve them. Run
    bun run build:server (or full bun run build) before
    desktop dev.
  • daemon-keypair.ts: replaced require('node:crypto') with top-level
    randomBytes import so it builds cleanly to ESM.

Dev port scheme (verified against the IANA port list — the 17000–17999
range has only 10 registered ports; 5174–5189 are all unassigned):

ServiceBeforeAfterWhy
Daemon (HTTP+WS)676717687Sparse IANA range; visually echoes Paseo with a leading 1
Vite dev server51735179Adjacent to Vite default; sits in a quiet IANA zone

Verification

Manually ran the full stack end-to-end:

$ bun run typecheck # clean
$ bun test # 44 pass, 2 pre-existing fails in connection-offer.test.ts
$ bun run lint # 0 errors
$ bun run build # clean
# End-to-end
$ cd packages/desktop && bun run dev # builds dist + launches Electron
$ curl http://127.0.0.1:17687/api/health
{"status":"ok","serverId":"srv_uXWlD-VmFsmKkB66",...}
# Vite-served web renderer inside Electron opens a 'web-...' WS session
# back through the :5179 proxy

Env overrides remain available: SUPAPLANE_LISTEN_PORT,
SUPAPLANE_DAEMON_PORT, SUPAPLANE_WEB_PORT, VITE_PORT.

Test status

PackageBeforeAfter
connection-offer.test.ts2 fail2 fail (pre-existing — these assert supaplane.run but the encoder produces supaplane.com; unrelated to this PR)
config.test.ts1 failpass (was asserting default listenPort === 6767, updated to 17687)

Net: 3 → 2 pre-existing failures, 0 new failures.

Consequences

  • @echohello/{protocol,server}exports now resolve to dist/
    rather than src/. Anyone importing these workspaces from Node
    (not via Bundler resolution) must run bun run build first.
    Mobile/Vite/web keep working via their bundler resolution.
  • Vite default port moved off 5173. Any external tooling that
    hard-codes 5173 (browser bookmarks, scripts) needs to be updated
    to 5179.
  • Daemon default port moved off 6767. The CLI defaults in
    cli/src/commands/daemon.ts still say 6767 in their help text
    (left intentionally — they're display strings); env override is
    available via --endpoint.

Testing

  • bun run typecheck clean
  • bun run build clean
  • bun test (no new failures; one pre-existing failure now passes)
  • Manual end-to-end: Vite (5179) + Electron-rendered web +
    embedded daemon (17687) — health endpoint responds, WS session opens
  • Eyeball review requested for the dev-port choice + desktop
    exports flip

opencode added 2 commits July 18, 2026 00:11
Adds the three-screen MVP on top of @echohello/client:
- connect: manual ws:// endpoint + label, saved to AsyncStorage,
connects via SupaplaneClient
- sessions: workspace list grouped by freshness, tap to drill in
- session: transcript + composer (send/abort/start) bound to
ClientCommand wire types
Shared infrastructure:
- zustand connection-store: single SupaplaneClient instance,
status, workspaces, sessions, per-session event buffer
- AsyncStorage wrapper (v3 API: setMany/removeMany) for the
saved endpoint and TOFU-pinned server fingerprint
- dark theme tokens, Button, TextField, ConnectionBanner
Bundler plumbing: metro.config.cjs with explicit watchFolders
and nodeModulesPaths so Bun's hoisting doesn't trip the
resolver on a monorepo root.
Co-authored-by: opencode <opencode@echohello.dev>
Desktop build wiring:
- packages/desktop/tsconfig.build.json emits ESM to dist/
- packages/desktop/package.json: dev now runs tsc -> electron
- main.js (dist) replaces main.ts as the package entry, and
preload.js resolves to the dist sibling
- @echohello/server and @echohello/protocol exports point at
dist/ so Electron's Node can resolve them. Run
'bun run build:server' (or 'bun run build') before
'desktop dev'.
Dev port scheme (avoiding Paseo + Vite + Metro defaults):
- Daemon listenPort: 6767 -> 17687 (IANA-sparse range,
visually echoes 6767)
- Vite port: 5173 -> 5179 (adjacent to Vite default so it
reads as 'the Supaplane Vite port')
- vite.config.ts reads SUPAPLANE_DAEMON_PORT and VITE_PORT
envs; defaults updated
- AGENTS.md + docs/development.md updated to reflect the
new ports
Server hygiene:
- daemon-keypair.ts: replace require('node:crypto') with
a top-level import so it builds cleanly to ESM
Co-authored-by: opencode <opencode@echohello.dev>
@johnnyhuy
johnnyhuy merged commit 849f8f6 into mainJul 17, 2026
1 check passed
@github-actionsgithub-actionsBot mentioned this pull request Jul 20, 2026
johnnyhuy added a commit that referenced this pull request Aug 9, 2026
…687/5179) (#1)
* feat(app): scaffold mobile UI for connect/sessions/transcript
Adds the three-screen MVP on top of @echohello/client:
- connect: manual ws:// endpoint + label, saved to AsyncStorage,
connects via SupaplaneClient
- sessions: workspace list grouped by freshness, tap to drill in
- session: transcript + composer (send/abort/start) bound to
ClientCommand wire types
Shared infrastructure:
- zustand connection-store: single SupaplaneClient instance,
status, workspaces, sessions, per-session event buffer
- AsyncStorage wrapper (v3 API: setMany/removeMany) for the
saved endpoint and TOFU-pinned server fingerprint
- dark theme tokens, Button, TextField, ConnectionBanner
Bundler plumbing: metro.config.cjs with explicit watchFolders
and nodeModulesPaths so Bun's hoisting doesn't trip the
resolver on a monorepo root.
Co-authored-by: opencode <opencode@echohello.dev>
* chore(dev): wire desktop build + shift dev ports off 6767/5173
Desktop build wiring:
- packages/desktop/tsconfig.build.json emits ESM to dist/
- packages/desktop/package.json: dev now runs tsc -> electron
- main.js (dist) replaces main.ts as the package entry, and
preload.js resolves to the dist sibling
- @echohello/server and @echohello/protocol exports point at
dist/ so Electron's Node can resolve them. Run
'bun run build:server' (or 'bun run build') before
'desktop dev'.
Dev port scheme (avoiding Paseo + Vite + Metro defaults):
- Daemon listenPort: 6767 -> 17687 (IANA-sparse range,
visually echoes 6767)
- Vite port: 5173 -> 5179 (adjacent to Vite default so it
reads as 'the Supaplane Vite port')
- vite.config.ts reads SUPAPLANE_DAEMON_PORT and VITE_PORT
envs; defaults updated
- AGENTS.md + docs/development.md updated to reflect the
new ports
Server hygiene:
- daemon-keypair.ts: replace require('node:crypto') with
a top-level import so it builds cleanly to ESM
Co-authored-by: opencode <opencode@echohello.dev>
---------
Co-authored-by: opencode <opencode@echohello.dev>
johnnyhuy added a commit that referenced this pull request Aug 9, 2026
…687/5179) (#1)
* feat(app): scaffold mobile UI for connect/sessions/transcript
Adds the three-screen MVP on top of @echohello/client:
- connect: manual ws:// endpoint + label, saved to AsyncStorage,
connects via SupaplaneClient
- sessions: workspace list grouped by freshness, tap to drill in
- session: transcript + composer (send/abort/start) bound to
ClientCommand wire types
Shared infrastructure:
- zustand connection-store: single SupaplaneClient instance,
status, workspaces, sessions, per-session event buffer
- AsyncStorage wrapper (v3 API: setMany/removeMany) for the
saved endpoint and TOFU-pinned server fingerprint
- dark theme tokens, Button, TextField, ConnectionBanner
Bundler plumbing: metro.config.cjs with explicit watchFolders
and nodeModulesPaths so Bun's hoisting doesn't trip the
resolver on a monorepo root.
Co-authored-by: opencode <opencode@echohello.dev>
* chore(dev): wire desktop build + shift dev ports off 6767/5173
Desktop build wiring:
- packages/desktop/tsconfig.build.json emits ESM to dist/
- packages/desktop/package.json: dev now runs tsc -> electron
- main.js (dist) replaces main.ts as the package entry, and
preload.js resolves to the dist sibling
- @echohello/server and @echohello/protocol exports point at
dist/ so Electron's Node can resolve them. Run
'bun run build:server' (or 'bun run build') before
'desktop dev'.
Dev port scheme (avoiding Paseo + Vite + Metro defaults):
- Daemon listenPort: 6767 -> 17687 (IANA-sparse range,
visually echoes 6767)
- Vite port: 5173 -> 5179 (adjacent to Vite default so it
reads as 'the Supaplane Vite port')
- vite.config.ts reads SUPAPLANE_DAEMON_PORT and VITE_PORT
envs; defaults updated
- AGENTS.md + docs/development.md updated to reflect the
new ports
Server hygiene:
- daemon-keypair.ts: replace require('node:crypto') with
a top-level import so it builds cleanly to ESM
Co-authored-by: opencode <opencode@echohello.dev>
---------
Co-authored-by: opencode <opencode@echohello.dev>
johnnyhuy added a commit that referenced this pull request Aug 9, 2026
…687/5179) (#1)
* feat(app): scaffold mobile UI for connect/sessions/transcript
Adds the three-screen MVP on top of @echohello/client:
- connect: manual ws:// endpoint + label, saved to AsyncStorage,
connects via SupaplaneClient
- sessions: workspace list grouped by freshness, tap to drill in
- session: transcript + composer (send/abort/start) bound to
ClientCommand wire types
Shared infrastructure:
- zustand connection-store: single SupaplaneClient instance,
status, workspaces, sessions, per-session event buffer
- AsyncStorage wrapper (v3 API: setMany/removeMany) for the
saved endpoint and TOFU-pinned server fingerprint
- dark theme tokens, Button, TextField, ConnectionBanner
Bundler plumbing: metro.config.cjs with explicit watchFolders
and nodeModulesPaths so Bun's hoisting doesn't trip the
resolver on a monorepo root.
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
* chore(dev): wire desktop build + shift dev ports off 6767/5173
Desktop build wiring:
- packages/desktop/tsconfig.build.json emits ESM to dist/
- packages/desktop/package.json: dev now runs tsc -> electron
- main.js (dist) replaces main.ts as the package entry, and
preload.js resolves to the dist sibling
- @echohello/server and @echohello/protocol exports point at
dist/ so Electron's Node can resolve them. Run
'bun run build:server' (or 'bun run build') before
'desktop dev'.
Dev port scheme (avoiding Paseo + Vite + Metro defaults):
- Daemon listenPort: 6767 -> 17687 (IANA-sparse range,
visually echoes 6767)
- Vite port: 5173 -> 5179 (adjacent to Vite default so it
reads as 'the Supaplane Vite port')
- vite.config.ts reads SUPAPLANE_DAEMON_PORT and VITE_PORT
envs; defaults updated
- AGENTS.md + docs/development.md updated to reflect the
new ports
Server hygiene:
- daemon-keypair.ts: replace require('node:crypto') with
a top-level import so it builds cleanly to ESM
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
---------
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
This was referenced Aug 9, 2026
Sign up for freeto 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

@johnnyhuy