Skip to content

Commit c0e92b3

Browse files
committed
feat(orbit): add sign-in, runner mode, and settings wiring
1 parent 1db4e05 commit c0e92b3

20 files changed

Lines changed: 2513 additions & 107 deletions

File tree

docs/mobile-ios-cloudflare-blueprint.md

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,26 @@ This document is the canonical implementation plan for shipping CodexMonitor on
2727
- `src-tauri/src/remote_backend/orbit_ws_transport.rs`
2828
- Current transport behavior:
2929
- TCP transport remains intact (existing remote path preserved).
30-
- Orbit WS transport is implemented for connect/read/write + request/response routing.
31-
- Reconnect/backoff and replay/resync hardening are still pending.
30+
- Orbit WS transport is implemented for connect/read/write + request/response routing, including line-delimited frame splitting.
31+
- App transport is currently single-connection (no client-side reconnect loop yet).
32+
- Daemon Orbit runner mode includes reconnect/backoff for outbound Orbit WS.
3233
- Remote provider settings baseline is implemented:
3334
- `remoteBackendProvider`: `"tcp" | "orbit"`
3435
- `remoteBackendHost`, `remoteBackendToken`
3536
- `orbitDeploymentMode`, `orbitWsUrl`, `orbitAuthUrl`
3637
- `orbitRunnerName`, `orbitAutoStartRunner`
3738
- `orbitUseAccess`, `orbitAccessClientId`, `orbitAccessClientSecretRef`
39+
- Orbit remote operations are implemented in app and daemon wiring via shared core:
40+
- `orbit_connect_test`
41+
- `orbit_sign_in_start`
42+
- `orbit_sign_in_poll` (stores token to app settings on authorization)
43+
- `orbit_sign_out` (best-effort logout + token clear)
44+
- `orbit_runner_start`
45+
- `orbit_runner_stop`
46+
- `orbit_runner_status`
47+
- Settings UI now includes Orbit provider setup/actions in `SettingsView`:
48+
- deployment mode, URLs, runner name, access fields, connect/sign-in/sign-out, runner start/stop/status
49+
- inline device-code polling flow wired to `orbit_sign_in_poll`
3850
- Remote notification forwarding currently handles only:
3951
- `app-server-event`
4052
- `terminal-output`
@@ -123,7 +135,8 @@ Implemented structure:
123135
Current status:
124136

125137
- Done: transport split + provider routing + Orbit WS connect/read/write path.
126-
- Pending: reconnect strategy, backoff policy, replay/resync contract integration.
138+
- Done: WebSocket payload parsing split to protocol lines before JSON-RPC dispatch.
139+
- Pending: app-side reconnect strategy and replay/resync contract integration.
127140

128141
## 2) Add bridge configuration to settings model
129142

@@ -173,6 +186,11 @@ Responsibilities:
173186
- Persist last logs ring buffer.
174187
- Auto-start on app launch if enabled.
175188

189+
Current implementation:
190+
191+
- Basic runner lifecycle controls are implemented via Tauri commands in `src-tauri/src/orbit/mod.rs` and daemon Orbit mode args in `src-tauri/src/bin/codex_monitor_daemon.rs`.
192+
- Full background service management (LaunchAgent install/remove, log viewer, lifecycle recovery after app restart) remains pending.
193+
176194
Potential implementations:
177195

178196
- Embedded task in app process (faster iteration).
@@ -195,6 +213,12 @@ Behavior:
195213
- Translate Orbit-relayed JSON-RPC to existing RPC handler + event bus.
196214
- Support runner reconnect and re-subscription behavior.
197215

216+
Current implementation status:
217+
218+
- Orbit mode args are implemented: `--orbit-url`, `--orbit-token`, `--orbit-auth-url`, `--orbit-runner-name`.
219+
- Orbit mode loop is implemented with reconnect/backoff, event forwarding, ping/pong handling, and `anchor.hello` metadata send.
220+
- Further Orbit-specific subscription/replay semantics remain pending until mobile Orbit client wiring is added.
221+
198222
## 6) Command parity scope (mobile phase)
199223

200224
Remote mode must support all commands exercised by the current mobile UI surface.
@@ -249,6 +273,21 @@ Required controls:
249273
- `Copy Pair Code` / `Show QR`
250274
- `View Logs` drawer
251275

276+
Current implementation status:
277+
278+
- Implemented now:
279+
- Provider selector, deployment mode selector
280+
- Orbit WS/Auth URL inputs
281+
- Runner name input
282+
- Access toggle + client id/secret ref fields
283+
- `Connect test`, `Sign In`, `Sign Out`, `Start Runner`, `Stop Runner`, `Refresh Status`
284+
- inline status/auth-code/verification URL display
285+
- Pending:
286+
- LaunchAgent install/remove controls
287+
- status badge with heartbeat metadata
288+
- `Copy Pair Code` / `Show QR`
289+
- logs drawer UI
290+
252291
UX behavior:
253292

254293
- Hide manual endpoint fields in hosted mode.

memory/decisions.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,17 @@ Type: preference
239239
Event: User requested removing all unreleased Cloudflare fallback/backport compatibility paths and tests.
240240
Action: Removed provider/url/session legacy compatibility aliases, removed legacy session URL injection logic, and deleted backport-focused tests from remote backend and settings models.
241241
Rule: For this unreleased Orbit workstream, keep settings and transport strictly canonical without backward-compat adapters.
242+
243+
## 2026-02-07 18:52
244+
Context: Orbit desktop setup UX and app/daemon dedup
245+
Type: decision
246+
Event: Orbit sign-in in Settings previously did not poll using the real device-code contract, and app/daemon each kept local settings parsing helpers.
247+
Action: Updated Settings sign-in flow to poll `orbit_sign_in_poll` with `deviceCode` until terminal status, added injectable Orbit service client for deterministic tests, and moved Orbit settings/url/token extraction helpers into `shared/orbit_core.rs` for app+daemon reuse.
248+
Rule: Keep Orbit auth/session behavior contract-driven (typed `deviceCode` flow) and share settings parsing/token helpers in `shared/orbit_core.rs` instead of adapter-local duplicates.
249+
250+
## 2026-02-07 19:39
251+
Context: Orbit token persistence parity hardening
252+
Type: decision
253+
Event: App and daemon both needed the same latest-state-safe token persistence behavior after Orbit poll/sign-out.
254+
Action: Added `update_remote_backend_token_core` in `shared/settings_core.rs` and switched both Orbit adapters to use it instead of cloning stale settings snapshots.
255+
Rule: Persist Orbit token changes only via shared settings-core mutation helpers to avoid app/daemon divergence and stale overwrite races.

memory/mistakes.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,53 @@ Rule: For large Rust modules, avoid full-file/head-tail rewrites unless line bou
3131
Root cause: Used brittle line-count/head-tail rewrite workflow while file contents were changing.
3232
Fix applied: Recovered from git snapshot and switched to explicit function-level patching.
3333
Prevention rule: Use patch hunks anchored on function signatures for high-churn files and verify file length/function inventory after each structural edit.
34+
35+
## 2026-02-07 18:52
36+
Context: Orbit sign-in Settings test stability
37+
Type: mistake
38+
Event: Initial Orbit sign-in test used fake timers with async polling and left the suite vulnerable to timer-state bleed/timeouts.
39+
Action: Reworked the test to use an injected Orbit client prop with deterministic mocked responses and real timer waits.
40+
Rule: For UI flows with delayed async polling, prefer dependency injection + deterministic mocks over fake timer orchestration unless timer control is strictly required.
41+
Root cause: The test depended on module-level service references and fake timer scheduling that conflicted with React async update timing.
42+
Fix applied: Added `orbitServiceClient` prop to `SettingsView`, switched test to pass explicit mock client, and removed fake timer manipulation.
43+
Prevention rule: Keep side-effect service dependencies injectable for settings workflows so tests can validate behavior without global spies/timer hacks.
44+
45+
## 2026-02-07 19:08
46+
Context: Orbit runner startup + settings token sync
47+
Type: mistake
48+
Event: Orbit runner startup resolved the wrong daemon binary name and Orbit auth actions updated backend token state without syncing `appSettings`, allowing stale token overwrite on later settings saves.
49+
Action: Updated runner binary resolution to prioritize `codex_monitor_daemon` naming and added explicit token sync (`onUpdateAppSettings`) after Orbit sign-in authorization and sign-out.
50+
Rule: For process launches and out-of-band settings mutations, keep UI state synchronized with backend writes and verify binary naming against packaged targets.
51+
Root cause: Assumed hyphenated daemon executable naming and relied on draft-only token updates after backend-side token mutation.
52+
Fix applied: Added candidate lookup for underscored daemon binary (with compatibility fallback) and implemented `syncRemoteBackendToken` in `SettingsView` plus regression tests.
53+
Prevention rule: Validate executable names against real build outputs and treat auth token changes as persisted settings updates, not UI-only draft changes.
54+
55+
## 2026-02-07 19:21
56+
Context: Orbit token sync follow-up regression
57+
Type: mistake
58+
Event: Token sync fix used stale `appSettings` snapshot during async sign-in polling, and URL token guard matched substring `token=` instead of exact query key.
59+
Action: Switched token sync merge source to a live settings ref and changed URL query-key detection to exact parameter-name matching with fragment-safe append behavior.
60+
Rule: Async settings writes must merge against latest state references, and query-parameter guards must match exact keys.
61+
Root cause: Closure-captured props were reused after user edits, and string containment check was too loose for query parsing.
62+
Fix applied: Added `latestSettingsRef`-based merge in `SettingsView`, plus exact query key parsing in `append_query` and expanded Orbit URL unit tests.
63+
Prevention rule: For async UI flows, avoid merging with captured props; for URL query logic, parse keys explicitly instead of substring scans.
64+
65+
## 2026-02-07 19:39
66+
Context: Orbit auth hardening follow-up (backend + shared URL/error helpers)
67+
Type: mistake
68+
Event: Orbit error-body truncation could panic on UTF-8 boundaries, websocket token query values were appended without URL encoding, and Orbit token persistence in app/daemon poll paths could overwrite newer settings snapshots.
69+
Action: Made error excerpt truncation UTF-8-boundary safe, percent-encoded appended query components, and introduced shared `update_remote_backend_token_core` to persist token updates from latest settings state in both app and daemon.
70+
Rule: For shared auth/network helpers, avoid raw byte string slicing and raw query interpolation, and persist token mutations through latest-state merge helpers rather than stale snapshots.
71+
Root cause: Manual string slicing/interpolation shortcuts and copy-pasted token persistence logic between adapters.
72+
Fix applied: Updated `shared/orbit_core.rs` and `shared/settings_core.rs`, then rewired `orbit/mod.rs` and daemon Orbit handlers to call the shared token updater.
73+
Prevention rule: Keep app/daemon settings mutation logic centralized in shared core APIs and require edge-case tests for UTF-8 and reserved query characters.
74+
75+
## 2026-02-07 19:50
76+
Context: Remote backend provider switch behavior
77+
Type: mistake
78+
Event: Switching remote provider in settings updated persisted config but left the in-memory remote transport cache active, so traffic continued over the old transport until restart/disconnect.
79+
Action: Added transport-change detection in app settings update flow and clear `state.remote_backend` when transport-affecting fields change.
80+
Rule: Any settings update that changes remote transport config must invalidate the cached remote backend client immediately.
81+
Root cause: Remote client cache lifecycle was only tied to disconnect/errors, not to transport settings mutations.
82+
Fix applied: Updated `src-tauri/src/settings/mod.rs` to compare previous vs updated transport settings and reset cached remote backend when they differ; added predicate unit tests.
83+
Prevention rule: Treat transport-config settings as cache keys and invalidate on change at the backend boundary, not only from UI handlers.

memory/todo.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Open
44
- [ ] 2026-02-07: Implement Orbit-only mobile remote foundation: Orbit transport in `remote_backend`, runner Orbit mode, hosted/self-host settings + pairing UX, and iOS keychain-backed auth storage.
55
- [ ] 2026-02-07: Harden Orbit WS transport with explicit reconnect/backoff + replay/resync handling for mobile reconnect flows.
6+
- [ ] 2026-02-07: Complete Orbit production readiness gaps after baseline wiring: secure secret storage (Keychain/keyring), LaunchAgent/background runner management, pairing QR/code UX, and app-side Orbit reconnect/resync handling.
67

78
## Done
89
- [x] 2026-02-07: Restored Sentry frontend reporting removed in `83a37da` (`@sentry/react`, `Sentry.init`, captureException callsites, and metrics instrumentation).

0 commit comments

Comments
 (0)