@@ -50,16 +50,6 @@ type Profile = {
5050
5151function profiles ( ) : Profile [ ] {
5252 return [
53- {
54- integrationID : Integration . ID . make ( "google-antigravity" ) ,
55- methodID : Integration . MethodID . make ( "oauth" ) ,
56- label : "Google account" ,
57- providerName : "AGY" ,
58- clientProfile : "ide" ,
59- clientID :
60- process . env . ANTIGRAVITY_OAUTH_CLIENT_ID ?? "884354919052-36trc1jjb3tguiac32ov6cod268c5blh.apps.googleusercontent.com" ,
61- clientSecret : process . env . ANTIGRAVITY_OAUTH_CLIENT_SECRET ?? "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" ,
62- } ,
6353 {
6454 integrationID : Integration . ID . make ( "google-antigravity-cli" ) ,
6555 methodID : Integration . MethodID . make ( "oauth" ) ,
@@ -87,52 +77,16 @@ const OnboardUserResponse = Schema.Struct({
8777 response : Schema . optional ( Schema . Struct ( { cloudaicompanionProject : Schema . optional ( Schema . String ) } ) ) ,
8878} )
8979
90- function post < S extends Schema . Top > (
91- http : HttpClient . HttpClient ,
92- url : string ,
93- token : string ,
94- body : unknown ,
95- schema : S ,
96- headers ?: Record < string , string > ,
97- ) {
98- return http
80+ function post < S extends Schema . Top > ( http : HttpClient . HttpClient , url : string , token : string , body : unknown , schema : S ) {
81+ return HttpClient . filterStatusOk ( http )
9982 . execute (
10083 HttpClientRequest . post ( url ) . pipe (
10184 HttpClientRequest . acceptJson ,
10285 HttpClientRequest . bearerToken ( token ) ,
10386 HttpClientRequest . bodyJsonUnsafe ( body ) ,
104- HttpClientRequest . setHeaders ( headers ?? { } ) ,
105- ) ,
106- )
107- . pipe (
108- Effect . tap ( ( response ) =>
109- response . status >= 400
110- ? response . text . pipe (
111- Effect . tap ( ( text ) =>
112- Effect . sync ( ( ) =>
113- console . error (
114- `[antigravity-debug] POST ${ url } sentBody=${ JSON . stringify ( body ) } sentHeaders=${ JSON . stringify ( headers ?? { } ) } -> ${ response . status } : ${ text } ` ,
115- ) ,
116- ) ,
117- ) ,
118- )
119- : Effect . void ,
12087 ) ,
121- Effect . flatMap ( HttpClientResponse . filterStatusOk ) ,
122- Effect . flatMap ( HttpClientResponse . schemaBodyJson ( schema ) ) ,
12388 )
124- }
125-
126- // Google's onboarding endpoints (unlike generateContent) appear to gate on
127- // client identity headers, not just the request body: OmniRoute's
128- // reverse-engineered client sends this exact "IDE-Node" fingerprint —
129- // distinct from both the CLI User-Agent and the native IDE Electron
130- // User-Agent — specifically for loadCodeAssist/onboardUser on the "ide"
131- // profile. Confirmed live: onboardUser 403s without it even with correct
132- // body metadata.
133- const ideNodeOnboardingHeaders = {
134- "User-Agent" : "antigravity/2.1.1 darwin/arm64 google-api-nodejs-client/10.3.0" ,
135- "X-Goog-Api-Client" : "gl-node/22.21.1" ,
89+ . pipe ( Effect . flatMap ( HttpClientResponse . schemaBodyJson ( schema ) ) )
13690}
13791
13892function get < S extends Schema . Top > ( http : HttpClient . HttpClient , url : string , token : string , schema : S ) {
@@ -145,43 +99,37 @@ function get<S extends Schema.Top>(http: HttpClient.HttpClient, url: string, tok
14599// backing this account. Required on every Code Assist call — the token
146100// alone isn't enough. Best-effort: a failure here still leaves the account
147101// usable, since onboarding can complete lazily on the first real request.
148- function discoverProject ( http : HttpClient . HttpClient , accessToken : string , clientProfile : ClientProfile ) {
149- // pluginType: "GEMINI" is the CLI's onboarding metadata; ideType:
150- // "ANTIGRAVITY" (OmniRoute's reverse-engineered shape) is what the real
151- // IDE app sends. Scoped to "ide" only — "cli" is confirmed working today.
152- const metadata = clientProfile === "ide" ? { ideType : "ANTIGRAVITY" } : { pluginType : "GEMINI" }
153- const headers = clientProfile === "ide" ? ideNodeOnboardingHeaders : undefined
102+ //
103+ // NOTE: only the CLI profile is registered (see profiles() below) — the
104+ // Antigravity IDE profile was removed. Its onboardUser call kept returning
105+ // Google's real, documented "BYOP" (bring-your-own-project) response for
106+ // consumer accounts: `done: true` but an empty `cloudaicompanionProject`,
107+ // because Google requires those accounts to link a real Google Cloud
108+ // project with a paid Gemini Code Assist license attached — confirmed by
109+ // reading OmniRoute's own source (antigravityProjectGate.ts, #11284), which
110+ // hits the identical wall and just marks those connections "degraded"
111+ // rather than actually resolving it. Not fixable from this side; CLI has no
112+ // such requirement and covers the same models.
113+ function discoverProject ( http : HttpClient . HttpClient , accessToken : string ) {
154114 return Effect . gen ( function * ( ) {
155- const loaded = yield * post ( http , loadCodeAssistUrl , accessToken , { metadata } , LoadCodeAssistResponse , headers )
115+ const loaded = yield * post (
116+ http ,
117+ loadCodeAssistUrl ,
118+ accessToken ,
119+ { metadata : { pluginType : "GEMINI" } } ,
120+ LoadCodeAssistResponse ,
121+ )
156122 if ( loaded . cloudaicompanionProject ) {
157123 return { projectID : loaded . cloudaicompanionProject , tier : loaded . currentTier ?. id }
158124 }
159- // onboardUser's request body uses snake_case tier_id, unlike every other
160- // camelCase field in these APIs — confirmed against OmniRoute's working
161- // client. Sending `tierId` here silently fails onboarding (Google's
162- // request validation just ignores/rejects the unrecognized field).
163- // Google returns the specific error FREE_TIER_USER_NOT_ELIGIBLE for
164- // paid-plan accounts onboarded with tier_id "free-tier" — confirmed
165- // live on a Google AI Pro account. loadCodeAssist's own response is `{}`
166- // for accounts with no existing project (no currentTier to read), so a
167- // fallback tier is unavoidable; OmniRoute's client defaults to
168- // "legacy-tier" rather than "free-tier" and works across paid plans.
169125 const onboarded = yield * post (
170126 http ,
171127 onboardUserUrl ,
172128 accessToken ,
173- { tier_id : loaded . currentTier ?. id ?? "legacy-tier" , metadata } ,
129+ { tier_id : loaded . currentTier ?. id ?? "legacy-tier" , metadata : { pluginType : "GEMINI" } } ,
174130 OnboardUserResponse ,
175- headers ,
176131 )
177- if ( onboarded . response ?. cloudaicompanionProject ) {
178- return { projectID : onboarded . response . cloudaicompanionProject , tier : loaded . currentTier ?. id }
179- }
180- // onboardUser's own response doesn't reliably carry the project once
181- // onboarding completes — OmniRoute re-fetches loadCodeAssist afterward
182- // to pick it up instead of trusting onboardUser's response shape.
183- const reloaded = yield * post ( http , loadCodeAssistUrl , accessToken , { metadata } , LoadCodeAssistResponse , headers )
184- return { projectID : reloaded . cloudaicompanionProject , tier : reloaded . currentTier ?. id ?? loaded . currentTier ?. id }
132+ return { projectID : onboarded . response ?. cloudaicompanionProject , tier : loaded . currentTier ?. id }
185133 } ) . pipe ( Effect . catch ( ( ) => Effect . succeed ( { projectID : undefined , tier : undefined } ) ) )
186134}
187135
@@ -214,7 +162,7 @@ function exchange(
214162 get ( http , userInfoUrl , token . access_token , UserInfo ) . pipe (
215163 Effect . catch ( ( ) => Effect . succeed ( { email : undefined as string | undefined } ) ) ,
216164 ) ,
217- discoverProject ( http , token . access_token , profile . clientProfile ) ,
165+ discoverProject ( http , token . access_token ) ,
218166 ] ,
219167 { concurrency : 2 } ,
220168 )
0 commit comments