Back to home@snail-vs

dsh-llm-oauth

OAuth login plugin for DeepSeek Harness (DSH), enabling subscription LLM accounts such as ChatGPT Plus/Pro to work without API keys.

Stars
0
Language
TypeScript
Created
Aug 22, 2026
Updated
Aug 22, 2026

Introduction

dsh-llm-oauth

Out-of-tree DeepSeek Harness (dsh) plugin: log in with subscription accounts (ChatGPT Plus/Pro, Claude Pro/Max, GitHub Copilot, …) via OAuth and use those models without an API key — the same capability opencode's /connect and the Codex CLI's codex login provide.

How it works

  • The @earendil-works/pi-ai package (already a dependency of dsh's dsh-llm-pi-ai) ships complete OAuth flows — browser PKCE (localhost:1455 callback) and headless device-code — plus automatic token refresh. This plugin wires those flows into dsh:
    • src/store.ts — a file-backed pi-ai CredentialStore ($DSH_HOME/.oauth.json, mode 0600, atomic writes, per-provider serialization) that pi-ai's auth resolution refreshes through.
    • src/service.ts — the llmOAuth service: login / logout / status over every OAuth-capable catalog provider.
    • src/interaction.ts — terminal interaction adapter (a Web GUI adapter will come with the client UI).
    • src/adapter.ts — (next milestone) a LlmAdapter registering the chatgpt provider route so logged-in models stream through ctx.llm.

Status / roadmap

  • Project scaffold, git
  • File credential store (CredentialStore contract)
  • OAuth login service + terminal interaction + CLI smoke script
  • LlmAdapter for the chatgpt route (pi-ai stream → dsh StreamChunk)
  • Mount as a profile plugin (dsh-llm-oauth in ~/.dsh/profiles/web)
  • Client settings UI (Settings → "模型登录": status + login/logout)
  • Import existing tokens from ~/.codex/auth.json / opencode auth.json

Mounted in the dsh web profile

Installed into ~/.dsh/profiles/web:

  • plugin package in node_modules/dsh-llm-oauth (host lib + client bundle, and a file:/data/code/ds-harness dependency in the profile package.json)

  • composition row in cordis.patch.yml (a new row must be an insert, not a bare override — a bare - id: x targets an already-composed row and skips with "entry not found"):

    - insert:
        - id: llm-oauth
          name: 'dsh-llm-oauth'
    

The client half declares dsh.client (inject: ['slots'], platform: 'web') and exports['./client'], so the web app serves and loads the Settings page.

Verify (after restarting the dsh web process)

  1. Restart dsh web so the Host loads the plugin row and the client bundle.
  2. Open Settings → 模型登录:
    • see the ChatGPT (Plus/Pro) status dot (red = not logged in).
    • click 浏览器登录 (opens auth.openai.com, callback on localhost:1455) or 设备码登录 (shows a code to enter at the verification link).
    • after authorization the status turns green with the account id.
  3. In the model picker, select provider chatgpt (e.g. gpt-5.4, gpt-5.5) and send a message — it streams via chatgpt.com/backend-api with the OAuth token (auto-refreshed).

CLI login is still available as an alternative: ./node_modules/.bin/tsx bin/login.ts login chatgpt.

Note: after rebuilding (pnpm build), re-copy lib/ into node_modules/dsh-llm-oauth — or run pnpm install in the profile to re-link the file: dependency.

Development

pnpm install
pnpm typecheck        # tsc --noEmit
pnpm build            # tsc -> lib/
pnpm login            # interactive login (browser PKCE or device code)
pnpm status           # show stored credentials

Caveats

  • ChatGPT / Claude subscription OAuth is a personal-use path subject to the providers' ToS — not for production or resale.
  • The browser flow binds localhost:1455; if Codex CLI or opencode is already listening there, use the device-code flow instead.
  • Plugin peer versions must match the installed dsh release (@deepseek-ai/dsh-llm, @deepseek-ai/cordis).

License

MIT