* feat: integrate GitHub OAuth device flow across runtimes Add GitHub OAuth device flow endpoints across runtimes Introduce GitHubSettings UI panel and sidebar entry Persist GitHub auth state in per-runtime storage * feat: add GitHub PR status and PR description generation Show PR status for the current branch in the Git view Generate a pull request description from the diff between base and head Expose prStatus, prCreate, and prMerge APIs in web and desktop clients * feat: add GitHub PR ready for review Add API to mark pull requests as ready for review Show a Ready button for draft PRs and reflect status in UI Handle token expiration and GraphQL errors when marking ready
4.8 KiB
GitHub Integration (Auth Foundation)
This repo now has a GitHub auth foundation intended to be reused by all future GitHub features (PRs/issues/worktrees/etc).
It provides:
- GitHub OAuth Device Flow connect UX
- persistent token storage per runtime
- a small runtime API surface for UI
- server-side Octokit usage (web runtime)
Scopes
Default scopes requested:
repo read:org workflow read:user user:email
Notes:
- Email is fetched from
/userwhen available, otherwise/user/emails(requiresuser:email). - Actions performed via this OAuth token are performed “as the user” (not a bot), but the OAuth App is visible under GitHub “Authorized OAuth Apps”.
UI
Settings entry:
packages/ui/src/components/sections/openchamber/GitHubSettings.tsx
Behavior:
- shows connected user card (avatar + name/email/login)
- Connect triggers Device Flow and polls until authorized
- Disconnect clears the stored token
Runtime API (UI)
RuntimeAPIs.github is optional (some environments may not expose it).
Types:
packages/ui/src/lib/api/types.ts(GitHubAPI,GitHubAuthStatus,GitHubDeviceFlowStart,GitHubDeviceFlowComplete)
Methods:
authStatus(): { connected, user?, scope? }authStart(): { deviceCode, userCode, verificationUri, verificationUriComplete?, expiresIn, interval, scope? }authComplete(deviceCode): { connected: true, user, scope? } | { connected: false, status?, error? }authDisconnect(): { removed: boolean }me?(): user(optional, mostly for debugging)
Implementations:
- Web:
packages/web/src/api/github.ts - Desktop:
packages/desktop/src/api/github.ts(calls Tauri commands) - VS Code:
packages/vscode/webview/api/github.ts(bridge messages)
Web Runtime (Express server)
Endpoints (JSON):
-
GET /api/github/auth/status- returns
{ connected: false }or{ connected: true, user, scope }
- returns
-
POST /api/github/auth/start- returns device flow payload:
{ deviceCode, userCode, verificationUri, verificationUriComplete?, expiresIn, interval, scope }
- returns device flow payload:
-
POST /api/github/auth/complete- request:
{ deviceCode } - returns either pending or success:
- pending:
{ connected: false, status, error } - success:
{ connected: true, user, scope }
- pending:
- request:
-
DELETE /api/github/auth- clears stored token
- returns
{ success: true, removed: boolean }
-
GET /api/github/me- returns the authenticated user summary
Code:
- endpoints:
packages/web/server/index.js - token store + config defaults:
packages/web/server/lib/github-auth.js - Octokit factory:
packages/web/server/lib/github-octokit.js - device flow helpers:
packages/web/server/lib/github-device-flow.js
Desktop Runtime (Tauri)
Tauri commands:
github_auth_statusgithub_auth_startgithub_auth_complete(param:deviceCode)github_auth_disconnectgithub_me
Code:
packages/desktop/src-tauri/src/commands/github.rs- wired in invoke handler:
packages/desktop/src-tauri/src/main.rs
VS Code Runtime
Bridge message types handled in extension:
api:github/auth:statusapi:github/auth:startapi:github/auth:completeapi:github/auth:disconnectapi:github/me
Code:
- storage + device flow +
/userfetch:packages/vscode/src/githubAuth.ts - bridge handlers:
packages/vscode/src/bridge.ts
Token Storage
-
Web/server runtime:
~/.config/openchamber/github-auth.json- file mode
0600best-effort
- file mode
-
Desktop runtime:
~/.config/openchamber/github-auth.json- file mode
0600best-effort
- file mode
-
VS Code runtime:
${extensionGlobalStorage}/github-auth.json- file mode
0600best-effort
- file mode
Stored fields (current shape; can evolve):
{
"accessToken": "…",
"scope": "…",
"tokenType": "bearer",
"createdAt": 1730000000000,
"user": {
"login": "…",
"id": 123,
"avatarUrl": "…",
"name": "…",
"email": "…"
}
}
Official OAuth App
Default OAuth client id is baked in:
Ov23liNd8TxDcMXtAHHM
Overrides:
- Web/server:
OPENCHAMBER_GITHUB_CLIENT_ID(env) - Scopes override (web/server):
OPENCHAMBER_GITHUB_SCOPES(env)
Note: UI editing of client id/scopes was intentionally removed to reduce user confusion.
How to Use in New Features
Preferred pattern:
- UI triggers new feature flows.
- Backend (web server or desktop/vscode runtime command/bridge) performs GitHub API calls using the stored token.
- Do not expose the token to the UI.
Web/server feature endpoints should:
- require
{ connected: true }state (return 401 if not connected) - use Octokit with
authset to stored token - accept repo/issue/pr identifiers from UI and fetch needed context
Future “context bootstrap” idea:
- Add endpoints that take
{ owner, repo, number }and return:- issue/PR body
- comments
- changed files (PR)
- diff/patch summary Then UI can start a session with a prefilled prompt.