@@ -2,6 +2,16 @@ import * as FsPlatform from "@effect/platform/FileSystem"
22import * as PathPlatform from "@effect/platform/Path"
33import { Effect } from "effect"
44
5+ import {
6+ authStreamMarkerExitCode ,
7+ type AuthStreamMarkers ,
8+ authStreamSucceeded ,
9+ authStreamVisibleLines ,
10+ codexLoginStreamMarkers ,
11+ githubLoginFailureMessage ,
12+ githubLoginStreamMarkers ,
13+ makeVisibleAuthStreamWriter
14+ } from "../shared/auth-stream-markers.js"
515import { request , requestTextStream , requestVoid } from "./api-http.js"
616import { asObject , type JsonRequest , type JsonValue } from "./api-json.js"
717import type { ControllerRuntime } from "./controller.js"
@@ -17,75 +27,18 @@ import type {
1727import { resolvePathFromCwd } from "./frontend-lib/usecases/path-helpers.js"
1828import type { ApiAuthRequiredError , ApiRequestError } from "./host-errors.js"
1929
20- type StreamMarkers = {
21- readonly success : string
22- readonly errorPrefix : string
23- }
24-
25- const codexLoginMarkers : StreamMarkers = {
26- success : "__DOCKER_GIT_CODEX_LOGIN_STATUS__:ok" ,
27- errorPrefix : "__DOCKER_GIT_CODEX_LOGIN_STATUS__:error:"
28- }
29-
30- const githubLoginMarkers : StreamMarkers = {
31- success : "__DOCKER_GIT_GITHUB_LOGIN_STATUS__:ok" ,
32- errorPrefix : "__DOCKER_GIT_GITHUB_LOGIN_STATUS__:error:"
33- }
34-
35- const isMarkerLine = ( line : string , markers : StreamMarkers ) : boolean =>
36- line . startsWith ( markers . success ) || line . startsWith ( markers . errorPrefix )
37-
38- const visibleLines = ( output : string , markers : StreamMarkers ) : ReadonlyArray < string > =>
39- output
40- . split ( / \r ? \n / u)
41- . map ( ( line ) => line . trim ( ) )
42- . filter ( ( line ) => line . length > 0 && ! isMarkerLine ( line , markers ) )
43-
44- const markerExitCode = ( output : string , markers : StreamMarkers ) : string | null => {
45- const failureLine = output
46- . split ( / \r ? \n / u)
47- . find ( ( line ) => line . startsWith ( markers . errorPrefix ) )
48-
49- return failureLine === undefined
50- ? null
51- : failureLine . slice ( markers . errorPrefix . length )
52- }
53-
54- const makeVisibleChunkWriter = ( markers : StreamMarkers ) => {
55- let pending = ""
56- const flushVisiblePending = ( ) => {
57- if ( pending . length > 0 && ! isMarkerLine ( pending , markers ) ) {
58- process . stdout . write ( pending )
59- }
60- }
61-
62- const writeVisibleChunk = ( chunk : string ) => {
63- pending += chunk
64- const lines = pending . split ( "\n" )
65- pending = lines . pop ( ) ?? ""
66-
67- for ( const line of lines ) {
68- if ( ! isMarkerLine ( line , markers ) ) {
69- process . stdout . write ( `${ line } \n` )
70- }
71- }
72- }
73-
74- return { flushVisiblePending, writeVisibleChunk }
75- }
76-
7730const codexLoginFailureMessage = ( output : string , exitCode : string | null ) : string => {
7831 if ( output . includes ( "429 Too Many Requests" ) ) {
7932 return "Codex device auth is rate-limited by OpenAI (429 Too Many Requests). Wait a few minutes and retry."
8033 }
8134
82- const detailedLine = visibleLines ( output , codexLoginMarkers )
35+ const detailedLine = authStreamVisibleLines ( output , codexLoginStreamMarkers )
8336 . findLast ( ( line ) => line . toLowerCase ( ) . includes ( "error" ) )
8437 if ( detailedLine !== undefined ) {
8538 return detailedLine
8639 }
8740
88- const lastLine = visibleLines ( output , codexLoginMarkers ) . at ( - 1 )
41+ const lastLine = authStreamVisibleLines ( output , codexLoginStreamMarkers ) . at ( - 1 )
8942 if ( lastLine !== undefined ) {
9043 return lastLine
9144 }
@@ -95,23 +48,6 @@ const codexLoginFailureMessage = (output: string, exitCode: string | null): stri
9548 : `Codex login failed (${ exitCode } ).`
9649}
9750
98- const githubLoginFailureMessage = ( output : string , exitCode : string | null ) : string => {
99- const detailedLine = visibleLines ( output , githubLoginMarkers )
100- . findLast ( ( line ) => line . toLowerCase ( ) . includes ( "failed" ) || line . toLowerCase ( ) . includes ( "error" ) )
101- if ( detailedLine !== undefined ) {
102- return detailedLine
103- }
104-
105- const lastLine = visibleLines ( output , githubLoginMarkers ) . at ( - 1 )
106- if ( lastLine !== undefined ) {
107- return lastLine
108- }
109-
110- return exitCode === null
111- ? "GitHub login stream ended without a completion marker."
112- : `GitHub login failed (${ exitCode } ).`
113- }
114-
11551const streamFailure = (
11652 method : "POST" ,
11753 path : string ,
@@ -127,21 +63,23 @@ const streamFailure = (
12763const requestMarkedAuthStream = (
12864 path : string ,
12965 body : JsonRequest ,
130- markers : StreamMarkers ,
66+ markers : AuthStreamMarkers ,
13167 failureMessage : ( output : string , exitCode : string | null ) => string
13268) =>
13369 Effect . gen ( function * ( _ ) {
134- const writer = makeVisibleChunkWriter ( markers )
135- const output = yield * _ ( requestTextStream ( "POST" , path , body , writer . writeVisibleChunk ) )
70+ const writer = makeVisibleAuthStreamWriter ( markers , ( chunk ) => {
71+ process . stdout . write ( chunk )
72+ } )
73+ const output = yield * _ ( requestTextStream ( "POST" , path , body , writer . writeChunk ) )
13674 writer . flushVisiblePending ( )
13775
138- if ( output . includes ( markers . success ) ) {
76+ if ( authStreamSucceeded ( output , markers ) ) {
13977 return output
14078 }
14179
14280 return yield * _ (
14381 Effect . fail < ApiRequestError > (
144- streamFailure ( "POST" , path , failureMessage ( output , markerExitCode ( output , markers ) ) )
82+ streamFailure ( "POST" , path , failureMessage ( output , authStreamMarkerExitCode ( output , markers ) ) )
14583 )
14684 )
14785 } )
@@ -164,7 +102,7 @@ const githubWebLogin = (
164102 token : null ,
165103 scopes : command . scopes
166104 } ,
167- githubLoginMarkers ,
105+ githubLoginStreamMarkers ,
168106 githubLoginFailureMessage
169107 ) . pipe (
170108 Effect . flatMap ( ( ) => request ( "GET" , "/auth/github/status" ) ) ,
@@ -193,7 +131,7 @@ export const codexLogin = (command: AuthCodexLoginCommand) =>
193131 requestMarkedAuthStream (
194132 "/auth/codex/login" ,
195133 { label : command . label } ,
196- codexLoginMarkers ,
134+ codexLoginStreamMarkers ,
197135 codexLoginFailureMessage
198136 ) . pipe ( Effect . asVoid )
199137
0 commit comments