packages/adapters/claude-local/src/server/__fixtures__/setup-token.md
setup-token characterization fixture2.1.205packages/adapters/claude-local/src/server/__fixtures__/setup-token.mdInvocation: all three child streams were pipes; stdin remained open for 8 seconds, then received a syntactically shaped synthetic code followed by LF (\ ).
124 from timeout; direct child termination in the equivalent harness: SIGKILL (-9).setup-token requires a PTY to expose and drive its interactive login UI. Supplying pipe stdin alone is insufficient.Normalized rendered text (spinner frames and terminal control sequences omitted):
Welcome to Claude Code v2.1.205
Opening browser to sign in…
Browser didn’t open? Use the url below to sign in (c to copy)
<REDACTED_AUTHORIZATION_URL>
Paste code here if prompted >
Authorization URL shape:
https://claude.com/cai/oauth/authorizeclient_id, code, code_challenge, code_challenge_method, redirect_uri, response_type, scope, stateCode-entry behavior:
#.* characters; the synthetic code itself is not rendered by Claude.Invalid-code result:
OAuth error: Request failed with status code 400
Press Enter to retry.
124; direct child termination in the harness: SIGKILL (-9).No real login or token was captured in this phase. Implementation should provisionally expect an opaque setup token shaped like sk-ant-oat01-<opaque> on the interactive terminal output stream after successful authorization. Both the exact prefix/length/delimiters and whether a non-PTY capture classifies the success line as stdout or stderr remain explicit assumptions. Confirm them once in the final live end-to-end implementation test before locking parser assertions.
claude --version; one pipe harness with a synthetic invalid code; and one PTY harness with bracketed-paste input showed the stream split, redacted URL structure, masked echo, HTTP 400 retry behavior, and controlled terminal exits. A literal scan of this document confirms it contains no authorization query values, browser code, or live token.
2.1.226A live run of claude setup-token on a real pseudo-terminal confirmed the prompt
contract is unchanged in substance from 2.1.205:
Browser didn't open? Use the url below to sign in (c to copy).https://claude.com, path /cai/oauth/authorize, the
same eight query keys (client_id, code, code_challenge,
code_challenge_method, redirect_uri, response_type, scope, state), no
fragment. The redirect_uri value host is https://platform.claude.com.Paste code here if prompted >.The live run recorded two terminal-rendering behaviors that the earlier normalized capture hid. The parser now handles both:
ESC[<n>G) sequence, so it emits no literal space
between two words. A parser that removes the control sequence glues the words
together. The parser now renders each horizontal-move sequence as one space.The success anchors and the token shape were not re-run live, because a real
login needs a subscription and an out-of-band browser. They stay as recorded in
setup-token-success.md: the before-anchor line
Your OAuth token (valid for 1 year):, the after-anchor line Store this token securely. You won't be able to see it again., and the token prefix
sk-ant-oat01-. The success screen renders its anchor words with the same
Cursor Horizontal Absolute spacing, so the same rendering fix applies to the
token parser.
An executable characterization test drives this live run. See
../setup-token-characterization.test.ts;
it is opt-in through RUN_CLAUDE_SETUP_TOKEN_CHARACTERIZATION=1.
2.1.19daytonaio/sandbox:0.8.0, headless, no
browser. Prompt phase only; no login was completed and no token was minted.The production sandbox image ships claude 2.1.19. A real Daytona smoke found
that this version emits a different login contract than 2.1.205 and 2.1.226.
The parser now accepts both contracts:
https://claude.ai, path
/oauth/authorize. The full pair is https://claude.ai/oauth/authorize.https://claude.com, path
/cai/oauth/authorize. The full pair is https://claude.com/cai/oauth/authorize.client_id, code,
code_challenge, code_challenge_method, redirect_uri, response_type,
scope, state. No fragment.redirect_uri value is the static callback
https://platform.claude.com/oauth/code/callback. A real 2.1.19 capture
confirmed this exact value, so the parser keeps the single pin.code value is a short opaque token. A real 2.1.19 capture measured a
four-character value, so the parser accepts a code value of one or more
characters.Paste code here if prompted >.Two rendering differences from 2.1.226:
2.1.19 prints the URL as plain text, not as an OSC 8
hyperlink.2.1.19 wraps the plain-text URL across several physical
lines at the terminal width, with no space at the wrap. The parser joins the
URL-character-only physical lines and validates only the final reassembled
string.Sanitized rendered form of the wrapped URL (placeholder values):
Browser didn't open? Use the url below to sign in (c to copy)
https://claude.ai/oauth/authorize?client_id=9d1c8f00-1a2b-3c4d-5e6f-708192a3b4c5&code=wZ9x&code_challenge=E9Melhoa2OwvFr
EMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&redirect_uri=https%3A%2F%2Fplatform.claude.com%2Foauth%2Fcode%2
Fcallback&response_type=code&scope=user%3Ainference&state=Xy7Kd2Pq9Rn4Vb8Lf1Mw6Zc3Hj0Tg5Us
Paste code here if prompted >