@@ -6,6 +6,7 @@ import * as Fiber from "effect/Fiber"
66import type * as Scope from "effect/Scope"
77import * as Stream from "effect/Stream"
88
9+ import { stripAnsi , writeChunkToFd } from "../shell/ansi-strip.js"
910import { resolveDefaultDockerUser , resolveDockerVolumeHostPath } from "../shell/docker-auth.js"
1011import { AuthError , CommandFailedError } from "../shell/errors.js"
1112
@@ -20,70 +21,9 @@ import { AuthError, CommandFailedError } from "../shell/errors.js"
2021// INVARIANT: OAuth credentials are stored in ~/.gemini directory within account path
2122// COMPLEXITY: O(command)
2223
23- const outputWindowSize = 262_144
24-
25- const ansiEscape = "\u001B"
26- const ansiBell = "\u0007"
27-
28- const isAnsiFinalByte = ( codePoint : number | undefined ) : boolean =>
29- codePoint !== undefined && codePoint >= 0x40 && codePoint <= 0x7E
30-
31- const skipCsiSequence = ( raw : string , start : number ) : number => {
32- const length = raw . length
33- let index = start + 2
34- while ( index < length ) {
35- const codePoint = raw . codePointAt ( index )
36- if ( isAnsiFinalByte ( codePoint ) ) {
37- return index + 1
38- }
39- index += 1
40- }
41- return index
42- }
43-
44- const skipOscSequence = ( raw : string , start : number ) : number => {
45- const length = raw . length
46- let index = start + 2
47- while ( index < length ) {
48- const char = raw [ index ] ?? ""
49- if ( char === ansiBell ) {
50- return index + 1
51- }
52- if ( char === ansiEscape && raw [ index + 1 ] === "\\" ) {
53- return index + 2
54- }
55- index += 1
56- }
57- return index
58- }
59-
60- const skipEscapeSequence = ( raw : string , start : number ) : number => {
61- const next = raw [ start + 1 ] ?? ""
62- if ( next === "[" ) {
63- return skipCsiSequence ( raw , start )
64- }
65- if ( next === "]" ) {
66- return skipOscSequence ( raw , start )
67- }
68- return Math . min ( raw . length , start + 2 )
69- }
70-
71- const stripAnsi = ( raw : string ) : string => {
72- const cleaned : Array < string > = [ ]
73- let index = 0
24+ type GeminiAuthResult = "success" | "failure" | "pending"
7425
75- while ( index < raw . length ) {
76- const current = raw [ index ] ?? ""
77- if ( current !== ansiEscape ) {
78- cleaned . push ( current )
79- index += 1
80- continue
81- }
82- index = skipEscapeSequence ( raw , index )
83- }
84-
85- return cleaned . join ( "" )
86- }
26+ const outputWindowSize = 262_144
8727
8828// Detect successful authentication in Gemini CLI output
8929const authSuccessPatterns = [
@@ -102,7 +42,7 @@ const authFailurePatterns = [
10242 "Authentication cancelled"
10343]
10444
105- const detectAuthResult = ( output : string ) : "success" | "failure" | "pending" => {
45+ const detectAuthResult = ( output : string ) : GeminiAuthResult => {
10646 const normalized = stripAnsi ( output ) . toLowerCase ( )
10747
10848 for ( const pattern of authSuccessPatterns ) {
@@ -176,18 +116,10 @@ const startDockerProcess = (
176116 )
177117 )
178118
179- const writeChunkToFd = ( fd : number , chunk : Uint8Array ) : void => {
180- if ( fd === 2 ) {
181- process . stderr . write ( chunk )
182- return
183- }
184- process . stdout . write ( chunk )
185- }
186-
187119const pumpDockerOutput = (
188120 source : Stream . Stream < Uint8Array , PlatformError > ,
189121 fd : number ,
190- resultBox : { value : "success" | "failure" | "pending" }
122+ resultBox : { value : GeminiAuthResult }
191123) : Effect . Effect < void , PlatformError > => {
192124 const decoder = new TextDecoder ( "utf-8" )
193125 let outputWindow = ""
@@ -214,7 +146,7 @@ const pumpDockerOutput = (
214146}
215147
216148const resolveGeminiLoginResult = (
217- result : "success" | "failure" | "pending" ,
149+ result : GeminiAuthResult ,
218150 exitCode : number
219151) : Effect . Effect < void , AuthError | CommandFailedError > =>
220152 Effect . gen ( function * ( _ ) {
@@ -272,7 +204,7 @@ export const runGeminiOauthLoginWithPrompt = (
272204 const spec = buildDockerGeminiAuthSpec ( cwd , hostPath , options . image , options . containerPath )
273205 const proc = yield * _ ( startDockerProcess ( executor , spec ) )
274206
275- const resultBox : { value : "success" | "failure" | "pending" } = { value : "pending" }
207+ const resultBox : { value : GeminiAuthResult } = { value : "pending" }
276208 const stdoutFiber = yield * _ ( Effect . forkScoped ( pumpDockerOutput ( proc . stdout , 1 , resultBox ) ) )
277209 const stderrFiber = yield * _ ( Effect . forkScoped ( pumpDockerOutput ( proc . stderr , 2 , resultBox ) ) )
278210
0 commit comments