feat: sign in to a backend from codeoid, instead of pasting an API key (#331) wired the mechanism and one backend. Claude works; codex, gemini and qwen do not.
What is already generic
The broker (src/daemon/auth/backend-login.ts) has no per-backend branching. A backend is a LoginFlow entry:
{
backend: "codex",
resolve(): { file, args } | null, // the login command, or null if absent
urlPattern: RegExp, // the authorize URL in raw terminal output
failurePattern: RegExp, // the vendor's own rejection
codeHint: string, // what the user brings back
extractSecret(transcript): { key, value } | null,
}
…plus the backend id in three places: LoginBackend, LOGIN_CAPABLE_BACKENDS (protocol), and loginBackendField (the zod enum). The UI needs CREDENTIAL_KEY and LABEL entries in BackendLoginPanel.tsx and nothing else — the panel renders for any tab whose id is login-capable.
Everything hard is already done and shared: the pty, timeouts, cancellation by process group, single-attempt-per-backend, redaction, and the rule that a pty-echoed input is never mistaken for the vendor's answer.
What is NOT generic, and why this is not one commit
The patterns can only be written after watching the real command. Every assumption in the Claude flow came from a captured transcript, and two of them were surprises: setup-token writes nothing at all to a pipe (it needs a pty, it does not degrade), and it keeps running after a rejected code to offer a retry. Neither is in any documentation. Guessing the equivalents for three more CLIs would produce three plausible flows that fail on contact.
So each backend is: capture a transcript, read it, write the entry, add a fake-command test modelled on that transcript.
Per backend
Note on extractSecret
Returning null is not failure — it means "nothing for codeoid to store", and the attempt then succeeds on the command's exit status. A backend that writes its credential to disk (codex and qwen both do) may legitimately need no secret extraction at all. That is the easy case.
feat: sign in to a backend from codeoid, instead of pasting an API key(#331) wired the mechanism and one backend. Claude works; codex, gemini and qwen do not.What is already generic
The broker (
src/daemon/auth/backend-login.ts) has no per-backend branching. A backend is aLoginFlowentry:…plus the backend id in three places:
LoginBackend,LOGIN_CAPABLE_BACKENDS(protocol), andloginBackendField(the zod enum). The UI needsCREDENTIAL_KEYandLABELentries inBackendLoginPanel.tsxand nothing else — the panel renders for any tab whose id is login-capable.Everything hard is already done and shared: the pty, timeouts, cancellation by process group, single-attempt-per-backend, redaction, and the rule that a pty-echoed input is never mistaken for the vendor's answer.
What is NOT generic, and why this is not one commit
The patterns can only be written after watching the real command. Every assumption in the Claude flow came from a captured transcript, and two of them were surprises:
setup-tokenwrites nothing at all to a pipe (it needs a pty, it does not degrade), and it keeps running after a rejected code to offer a retry. Neither is in any documentation. Guessing the equivalents for three more CLIs would produce three plausible flows that fail on contact.So each backend is: capture a transcript, read it, write the entry, add a fake-command test modelled on that transcript.
Per backend
codex login. codeoid already detects the result (~/.codex/auth.json, see the Codex settings tab), so only the interactive half is missing. Open question worth resolving first: whether it is a paste-a-code flow at all or a localhost callback, which a remote daemon cannot receive. If it is localhost-only, that is a different design (a tunnelled callback), not aLoginFlow— say so in the issue rather than forcing it.~/.qwen/oauth_creds.jsonand picksqwen-oauthoveropenaiwhen it exists (src/daemon/providers/qwen/index.ts), so the credential path is proven; only the login is out-of-band today.Note on
extractSecretReturning
nullis not failure — it means "nothing for codeoid to store", and the attempt then succeeds on the command's exit status. A backend that writes its credential to disk (codex and qwen both do) may legitimately need no secret extraction at all. That is the easy case.