Skip to content

feat: P1 — connect, API-key auth, session list, live transcript - #1

Merged
saucam merged 1 commit into
mainfrom
feat/p1-connect-auth-attach
Jul 7, 2026
Merged

feat: P1 — connect, API-key auth, session list, live transcript#1
saucam merged 1 commit into
mainfrom
feat/p1-connect-auth-attach

Conversation

@saucam

@saucam saucam commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

What

All of P1 from docs/mobile-app-design.md §10, built on the published @codeoid/protocol@0.1.0 + @codeoid/core@0.1.0:

  • Connect screen — daemon URL entry → /health + /config discovery → zid_sk_… API-key exchange at the daemon's same-origin /oauth2/token proxy → credentials in Keychain/Keystore (expo-secure-store), JWT held in memory only and re-minted on every reconnect (getToken). Auto-reconnects with stored credentials on launch. Google OAuth stays P3 (codeoid#42).
  • Connection singleton — one CodeoidClient + MessageStore + ResumeCursors per daemon; every broadcast routed through store.ingest(msg, cursors); capabilities declared: parts, replay.chunked, replay.resume, send.idempotency. AppState (foreground) + NetInfo (connectivity regained) → reconnectNow().
  • Session listsession.list via waitForResult correlation, kept live from session.status_change / session.info_update, pull-to-refresh, protocol-mismatch banner, sign-out.
  • Transcript — attach on entry (incremental resume when a cursor exists), re-attach on every connected transition, detach on leave, plain-text rows with per-message identity labels and tool phase lines, composer minting one clientMsgId per send. FlashList + streaming markdown arrive in P2.

Metro + TS-source packages (the flagged P1 risk)

The handoff's assumption was right to worry: Metro resolves the packages' exports → ./src/index.ts fine, but does not apply the TS-ESM .js → .ts redirect to their internal relative imports (from "./types.js"). metro.config.js adds a minimal resolveRequest fallback that retries a failed .js resolution without the extension — it cannot affect specifiers that already resolve.

Verification

  • tsc --noEmit, eslint ., and npx expo export --platform android (full Metro → Hermes bundle) all clean.
  • Headless e2e against a live daemon using the exact app wiring: discovery → key exchange (all 9 requested scopes granted) → auth.ok (protocol v1 both sides) → session.list (17 sessions) → read-only attach replaying 1015 messages through store.ingest(). The test daemon build predates replay.resume, so the cursor path correctly fell back to full replay; incremental re-attach still needs a current daemon to observe live.
  • Device-only assumptions still to confirm on first run (design doc "assumptions" list): RN WebSocket addEventListener, SecureStore, AppState resume behavior.

🤖 Generated with Claude Code

Implements design doc §10 P1 on the published @codeoid/protocol +
@codeoid/core packages:

- Connect screen: /health + /config discovery, zid_sk_ API-key exchange
  via the daemon's /oauth2/token proxy (scoped request — a scope-less
  JWT would have every verb denied), credentials in the device
  Keychain/Keystore, JWT re-minted on every reconnect via getToken.
- Connection singleton: CodeoidClient (parts, replay.chunked,
  replay.resume, send.idempotency declared) + MessageStore +
  ResumeCursors; AppState foreground + NetInfo regained-connectivity
  call reconnectNow().
- Session list: session.list with waitForResult correlation, kept live
  from session.status_change / session.info_update broadcasts,
  pull-to-refresh, protocol-version mismatch banner.
- Transcript: attach on entry with incremental-resume cursor, re-attach
  on every reconnect, detach on leave, plain-text rows (identity label
  per message, tool phase line), composer minting one clientMsgId per
  send.
- metro.config.js: resolver fallback retrying failed ".js" specifiers
  without the extension — the packages ship raw TS source with TS-ESM
  relative imports, which Metro does not redirect inside node_modules.

Verified headless against a live daemon: discovery → exchange (all 9
scopes granted) → auth.ok (protocol v1) → session.list (17 sessions) →
attach replayed 1015 messages through store.ingest(). Typecheck, lint,
and expo export (android) all clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@saucam
saucam merged commit 748eef2 into main Jul 7, 2026
1 check passed
Sign up for free to 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