Problem
The device-auth flow exists twice in src/index.ts: once in the standalone deviceLogin() function (lines 197-330) and again, near-identically, inline in the taskbounty_login handler (lines 628-744). The two copies have already diverged, and the only path that reaches deviceLogin() makes it redo work it cannot reach correctly.
Evidence
taskbounty_login handler, lines 628-643:
let start: DeviceStart | null = null;
try {
const res = await fetch(`${SITE_ORIGIN}/api/mcp/device/start`, { ... });
if (res.ok) start = (await res.json()) as DeviceStart;
} catch {
start = null;
}
if (!start) {
return await deviceLogin(clientName);
}
deviceLogin() (line 197+) then immediately performs the same /api/mcp/device/start POST again. So the only time deviceLogin() runs is when the first start call failed, and its first action is to retry the exact call that just failed, with no backoff. The polling loops in the two copies are otherwise duplicated logic (authorization_pending, slow_down, expired_token, access_denied, deadline handling), and they already differ: the inline copy prepends an instruction string to every result, the function copy does not. Divergence in auth-critical code is the bug.
Why it matters
This is the credential-bootstrap path for every creator tool. Two copies of an auth state machine means a fix or behavior change has to be made in both places or the two flows silently behave differently (they already do, re: the instruction text). It is also confusing for any agent attempting to fix or extend login.
Acceptance criteria
- The device-auth start + poll logic exists in exactly one place;
taskbounty_login and the fallback path both call it.
- The single implementation surfaces the approval instruction consistently regardless of which entry point triggered it.
- A regression test exercises the poll state machine (e.g. mocked
authorization_pending then success, and the expired_token path) against the single implementation.
Problem
The device-auth flow exists twice in
src/index.ts: once in the standalonedeviceLogin()function (lines 197-330) and again, near-identically, inline in thetaskbounty_loginhandler (lines 628-744). The two copies have already diverged, and the only path that reachesdeviceLogin()makes it redo work it cannot reach correctly.Evidence
taskbounty_loginhandler, lines 628-643:deviceLogin()(line 197+) then immediately performs the same/api/mcp/device/startPOST again. So the only timedeviceLogin()runs is when the firststartcall failed, and its first action is to retry the exact call that just failed, with no backoff. The polling loops in the two copies are otherwise duplicated logic (authorization_pending,slow_down,expired_token,access_denied, deadline handling), and they already differ: the inline copy prepends aninstructionstring to every result, the function copy does not. Divergence in auth-critical code is the bug.Why it matters
This is the credential-bootstrap path for every creator tool. Two copies of an auth state machine means a fix or behavior change has to be made in both places or the two flows silently behave differently (they already do, re: the instruction text). It is also confusing for any agent attempting to fix or extend login.
Acceptance criteria
taskbounty_loginand the fallback path both call it.authorization_pendingthen success, and theexpired_tokenpath) against the single implementation.