Skip to content

feat: add case.dev and Core to /login dropdown#7

Open
maxsonderby wants to merge 1 commit into
mainfrom
claude/frosty-mendel-e94d53
Open

feat: add case.dev and Core to /login dropdown#7
maxsonderby wants to merge 1 commit into
mainfrom
claude/frosty-mendel-e94d53

Conversation

@maxsonderby

Copy link
Copy Markdown
Contributor

Summary

  • Registers case.dev (device flow) and Core (OAuth device flow) as OAuth providers so they appear in the interactive /login selector
  • Providers survive model registry refresh() cycles (login/logout)

Test plan

  • Run linc, type /login, verify case.dev and Core appear in the dropdown
  • Select case.dev, confirm device flow starts and shows verification URL
  • Select Core, confirm OAuth device flow starts and shows verification URL

🤖 Generated with Claude Code

Register case.dev (device flow) and Core (OAuth device flow) as OAuth
providers so they appear in the interactive /login selector dropdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented May 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
linc-docs Ready Ready Preview, Comment May 16, 2026 9:36am

@thurgood-bot

thurgood-bot Bot commented May 16, 2026

Copy link
Copy Markdown

DB Cooper Database Review

No database-facing changes detected in the provided diff; this PR only adds OAuth provider wiring in the coding agent and does not touch schema, migrations, or queries. No DB risks identified.

No database risks found. Migrations and DB-impacting changes look safe.


DB review by DB Cooper | Re-run with /dbreview

@thurgood-bot

thurgood-bot Bot commented May 16, 2026

Copy link
Copy Markdown

Judicial Review

Adds case.dev and Core device-flow providers and registers them for /login, but there are a couple of hardcoded/overbroad defaults and some error-path gaps that could mask failures or over-grant access.

Findings: 0 critical, 2 warnings, 1 info

Security

⚠️ WARNING in packages/coding-agent/src/core/casedev-oauth.ts:64

Device-flow scope is hardcoded to full read/write for all services, which violates least-privilege and makes access breadth non-configurable.

Recommendation: Make scopes configurable (env/config) and default to the minimum required scope for CLI login; document expected scopes.

Error Handling

⚠️ WARNING in packages/coding-agent/src/core/casedev-oauth.ts:91

Polling ignores non-200/202/429/403/410 responses; server errors or malformed responses will silently loop until timeout, obscuring the real failure state.

Recommendation: Handle other non-2xx statuses explicitly with a descriptive error (include status code) or a bounded retry with backoff and a final failure message.

Architecture

ℹ️ INFO in packages/coding-agent/src/main.ts:817

Provider registration is performed in both main startup and ModelRegistry refresh, creating two registration paths that can drift or duplicate providers depending on registry behavior.

Recommendation: Centralize provider registration in one place (prefer ModelRegistry lifecycle) and ensure registration is idempotent to avoid duplicate entries after refresh.


Legal-Grade review by Thurgood | Re-review with /review

@thurgood-bot

thurgood-bot Bot commented May 16, 2026

Copy link
Copy Markdown

Oppenheimer Cleanup Review

Primary complexity is duplicated device-flow logic and repeated provider registration, which can be collapsed into shared helpers without changing behavior. No dead code proven; simplification is feasible but should be done with care to keep the login UX consistent.

Estimated LOC reduction: ~30 lines

📦 Collapse (2)

These items can be simplified or inlined to reduce complexity while preserving behavior.

  • packages/coding-agent/src/core/casedev-oauth.ts:15: Device-flow request/response types and polling logic duplicate the CLI login flow, increasing drift risk and maintenance cost. Repo-wide grep shows DeviceFlowStartResponse/DeviceFlowPollResponse/CoreDeviceCodeResponse/CoreTokenResponse appear only here and in packages/coding-agent/src/cli/login.ts, and the auth/cli endpoints are referenced only in those two files.

    Collapse by extracting shared device-flow helpers (types + polling) into a small module and have both the OAuth providers and CLI login call it, keeping exact error/timeout behavior.

  • packages/coding-agent/src/main.ts:820: Provider registration is duplicated in main startup and ModelRegistry.refresh, which is safe but repetitive. Repo-wide grep shows casedevOAuthProvider/coreOAuthProvider are only imported in main.ts and packages/coding-agent/src/core/model-registry.ts (besides their definition).

    Collapse registration into a single helper (e.g., registerDefaultOAuthProviders) invoked from both the ModelRegistry constructor/refresh or from a shared initializer to remove duplication without behavior change.


Cleanup review by Oppenheimer | Re-run with /cleanup

method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
scopes: { services: [{ service: "all", scopes: ["read", "write"] }] },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Device-flow scope is hardcoded to full read/write for all services, which violates least-privilege and makes access breadth non-configurable.

Suggestion: Make scopes configurable (env/config) and default to the minimum required scope for CLI login; document expected scopes.

signal: callbacks.signal,
});

if (pollRes.status === 200) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Polling ignores non-200/202/429/403/410 responses; server errors or malformed responses will silently loop until timeout, obscuring the real failure state.

Suggestion: Handle other non-2xx statuses explicitly with a descriptive error (include status code) or a bounded retry with backoff and a final failure message.

@@ -815,6 +817,10 @@ export async function main(args: string[]) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO: Provider registration is performed in both main startup and ModelRegistry refresh, creating two registration paths that can drift or duplicate providers depending on registry behavior.

Suggestion: Centralize provider registration in one place (prefer ModelRegistry lifecycle) and ensure registration is idempotent to avoid duplicate entries after refresh.


const FAR_FUTURE = Date.now() + 365 * 24 * 60 * 60 * 1000;

interface DeviceFlowStartResponse {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Device-flow request/response types and polling logic duplicate the CLI login flow, increasing drift risk and maintenance cost. Repo-wide grep shows DeviceFlowStartResponse/DeviceFlowPollResponse/CoreDeviceCodeResponse/CoreTokenResponse appear only here and in packages/coding-agent/src/cli/login.ts, and the auth/cli endpoints are referenced only in those two files.

Suggestion: Collapse by extracting shared device-flow helpers (types + polling) into a small module and have both the OAuth providers and CLI login call it, keeping exact error/timeout behavior.


const modelRegistry = new ModelRegistry(authStorage, getModelsPath());

// Register case.dev and Core as auth providers for /login

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Provider registration is duplicated in main startup and ModelRegistry.refresh, which is safe but repetitive. Repo-wide grep shows casedevOAuthProvider/coreOAuthProvider are only imported in main.ts and packages/coding-agent/src/core/model-registry.ts (besides their definition).

Suggestion: Collapse registration into a single helper (e.g., registerDefaultOAuthProviders) invoked from both the ModelRegistry constructor/refresh or from a shared initializer to remove duplication without behavior change.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a02390178

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +93 to +95
if (result.apiKey) {
return { access: result.apiKey, refresh: "", expires: FAR_FUTURE };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Persist login tokens where requests can read them

When this provider is selected from interactive /login, AuthStorage.login() stores the returned value as { type: "oauth", access: ... }, but the actual request path still only reads auth.json when data.casedev.type === "api_key" in AuthStorage.getApiKey() and isAuthenticated(). After this flow succeeds, hasAuth("casedev") can mark models available, but getApiKey() returns undefined, so the next model call fails with no API key; the same storage mismatch affects the new Core OAuth token unless the auth storage path is taught to return OAuth access tokens or these flows save the token in the existing API-key slot.

Useful? React with 👍 / 👎.

@Thurgood-AI Thurgood-AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Both device flows are well-implemented — proper abort signal handling, backoff for slow_down, correct token lifecycle (case.dev=long-lived key, Core=refresh rotation). Dual registration in main.ts + model-registry refresh() correctly handles the resetOAuthProviders() wipe. ⚖️

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.

2 participants