feat(antigravity-auth): separate google-auth module with dynamic port allocation
- Separate Google Antigravity auth to 'oh-my-opencode/google-auth' subpath - 'oh-my-opencode/auth' now exports OpenAI Codex auth plugin - Implement dynamic port allocation to avoid port conflicts - Add userAgent, requestId, sessionId fields for Antigravity API compatibility - Add debug logging for troubleshooting (ANTIGRAVITY_DEBUG=1) 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -17,10 +17,14 @@
|
|||||||
"types": "./dist/auth.d.ts",
|
"types": "./dist/auth.d.ts",
|
||||||
"import": "./dist/auth.js"
|
"import": "./dist/auth.js"
|
||||||
},
|
},
|
||||||
|
"./google-auth": {
|
||||||
|
"types": "./dist/google-auth.d.ts",
|
||||||
|
"import": "./dist/google-auth.js"
|
||||||
|
},
|
||||||
"./schema.json": "./dist/oh-my-opencode.schema.json"
|
"./schema.json": "./dist/oh-my-opencode.schema.json"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun build src/index.ts src/auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun run build:schema",
|
"build": "bun build src/index.ts src/auth.ts src/google-auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun run build:schema",
|
||||||
"build:schema": "bun run script/build-schema.ts",
|
"build:schema": "bun run script/build-schema.ts",
|
||||||
"clean": "rm -rf dist",
|
"clean": "rm -rf dist",
|
||||||
"prepublishOnly": "bun run clean && bun run build",
|
"prepublishOnly": "bun run clean && bun run build",
|
||||||
|
|||||||
12
src/auth.ts
12
src/auth.ts
@@ -1 +1,11 @@
|
|||||||
export { createGoogleAntigravityAuthPlugin as default } from "./auth/antigravity"
|
/**
|
||||||
|
* OpenAI Codex Auth Plugin re-export
|
||||||
|
*
|
||||||
|
* This module re-exports the OpenAI Codex OAuth authentication plugin,
|
||||||
|
* enabling users to authenticate with their ChatGPT Plus/Pro subscription.
|
||||||
|
*
|
||||||
|
* For Google Antigravity auth, use `oh-my-opencode/google-auth` instead.
|
||||||
|
*
|
||||||
|
* @see https://github.com/numman-ali/opencode-openai-codex-auth
|
||||||
|
*/
|
||||||
|
export { OpenAIAuthPlugin as default } from "opencode-openai-codex-auth"
|
||||||
|
|||||||
@@ -117,16 +117,10 @@ export function decodeState(encoded: string): OAuthState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the OAuth authorization URL with PKCE.
|
|
||||||
*
|
|
||||||
* @param projectId - Optional GCP project ID to include in state
|
|
||||||
* @param clientId - Optional custom client ID (defaults to ANTIGRAVITY_CLIENT_ID)
|
|
||||||
* @returns Authorization result with URL and verifier
|
|
||||||
*/
|
|
||||||
export async function buildAuthURL(
|
export async function buildAuthURL(
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
clientId: string = ANTIGRAVITY_CLIENT_ID
|
clientId: string = ANTIGRAVITY_CLIENT_ID,
|
||||||
|
port: number = ANTIGRAVITY_CALLBACK_PORT
|
||||||
): Promise<AuthorizationResult> {
|
): Promise<AuthorizationResult> {
|
||||||
const pkce = await generatePKCEPair()
|
const pkce = await generatePKCEPair()
|
||||||
|
|
||||||
@@ -135,9 +129,11 @@ export async function buildAuthURL(
|
|||||||
projectId,
|
projectId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const redirectUri = `http://localhost:${port}/oauth-callback`
|
||||||
|
|
||||||
const url = new URL(GOOGLE_AUTH_URL)
|
const url = new URL(GOOGLE_AUTH_URL)
|
||||||
url.searchParams.set("client_id", clientId)
|
url.searchParams.set("client_id", clientId)
|
||||||
url.searchParams.set("redirect_uri", ANTIGRAVITY_REDIRECT_URI)
|
url.searchParams.set("redirect_uri", redirectUri)
|
||||||
url.searchParams.set("response_type", "code")
|
url.searchParams.set("response_type", "code")
|
||||||
url.searchParams.set("scope", ANTIGRAVITY_SCOPES.join(" "))
|
url.searchParams.set("scope", ANTIGRAVITY_SCOPES.join(" "))
|
||||||
url.searchParams.set("state", encodeState(state))
|
url.searchParams.set("state", encodeState(state))
|
||||||
@@ -165,14 +161,16 @@ export async function exchangeCode(
|
|||||||
code: string,
|
code: string,
|
||||||
verifier: string,
|
verifier: string,
|
||||||
clientId: string = ANTIGRAVITY_CLIENT_ID,
|
clientId: string = ANTIGRAVITY_CLIENT_ID,
|
||||||
clientSecret: string = ANTIGRAVITY_CLIENT_SECRET
|
clientSecret: string = ANTIGRAVITY_CLIENT_SECRET,
|
||||||
|
port: number = ANTIGRAVITY_CALLBACK_PORT
|
||||||
): Promise<AntigravityTokenExchangeResult> {
|
): Promise<AntigravityTokenExchangeResult> {
|
||||||
|
const redirectUri = `http://localhost:${port}/oauth-callback`
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
client_id: clientId,
|
client_id: clientId,
|
||||||
client_secret: clientSecret,
|
client_secret: clientSecret,
|
||||||
code,
|
code,
|
||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
redirect_uri: ANTIGRAVITY_REDIRECT_URI,
|
redirect_uri: redirectUri,
|
||||||
code_verifier: verifier,
|
code_verifier: verifier,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -236,97 +234,88 @@ export async function fetchUserInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface CallbackServerHandle {
|
||||||
* Start a local HTTP server to receive OAuth callback.
|
port: number
|
||||||
*
|
waitForCallback: () => Promise<CallbackResult>
|
||||||
* @param timeoutMs - Timeout in milliseconds (default: 5 minutes)
|
close: () => void
|
||||||
* @returns Promise that resolves with callback result
|
}
|
||||||
*/
|
|
||||||
export function startCallbackServer(
|
export function startCallbackServer(
|
||||||
timeoutMs: number = 5 * 60 * 1000
|
timeoutMs: number = 5 * 60 * 1000
|
||||||
): Promise<CallbackResult> {
|
): CallbackServerHandle {
|
||||||
return new Promise((resolve, reject) => {
|
let server: ReturnType<typeof Bun.serve> | null = null
|
||||||
let server: ReturnType<typeof Bun.serve> | null = null
|
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
||||||
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
let resolveCallback: ((result: CallbackResult) => void) | null = null
|
||||||
|
let rejectCallback: ((error: Error) => void) | null = null
|
||||||
const cleanup = () => {
|
|
||||||
if (timeoutId) {
|
const cleanup = () => {
|
||||||
clearTimeout(timeoutId)
|
if (timeoutId) {
|
||||||
timeoutId = null
|
clearTimeout(timeoutId)
|
||||||
}
|
timeoutId = null
|
||||||
if (server) {
|
}
|
||||||
server.stop()
|
if (server) {
|
||||||
server = null
|
server.stop()
|
||||||
}
|
server = null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Set timeout
|
|
||||||
timeoutId = setTimeout(() => {
|
server = Bun.serve({
|
||||||
cleanup()
|
port: 0,
|
||||||
reject(new Error("OAuth callback timeout"))
|
fetch(request: Request): Response {
|
||||||
}, timeoutMs)
|
const url = new URL(request.url)
|
||||||
|
|
||||||
try {
|
if (url.pathname === "/oauth-callback") {
|
||||||
server = Bun.serve({
|
const code = url.searchParams.get("code") || ""
|
||||||
port: ANTIGRAVITY_CALLBACK_PORT,
|
const state = url.searchParams.get("state") || ""
|
||||||
fetch(request: Request): Response {
|
const error = url.searchParams.get("error") || undefined
|
||||||
const url = new URL(request.url)
|
|
||||||
|
let responseBody: string
|
||||||
if (url.pathname === "/oauth-callback") {
|
if (code && !error) {
|
||||||
const code = url.searchParams.get("code") || ""
|
responseBody =
|
||||||
const state = url.searchParams.get("state") || ""
|
"<html><body><h1>Login successful</h1><p>You can close this window.</p></body></html>"
|
||||||
const error = url.searchParams.get("error") || undefined
|
} else {
|
||||||
|
responseBody =
|
||||||
// Respond to browser
|
"<html><body><h1>Login failed</h1><p>Please check the CLI output.</p></body></html>"
|
||||||
let responseBody: string
|
}
|
||||||
if (code && !error) {
|
|
||||||
responseBody =
|
setTimeout(() => {
|
||||||
"<html><body><h1>Login successful</h1><p>You can close this window.</p></body></html>"
|
cleanup()
|
||||||
} else {
|
if (resolveCallback) {
|
||||||
responseBody =
|
resolveCallback({ code, state, error })
|
||||||
"<html><body><h1>Login failed</h1><p>Please check the CLI output.</p></body></html>"
|
}
|
||||||
}
|
}, 100)
|
||||||
|
|
||||||
// Schedule cleanup and resolve
|
return new Response(responseBody, {
|
||||||
setTimeout(() => {
|
status: 200,
|
||||||
cleanup()
|
headers: { "Content-Type": "text/html" },
|
||||||
resolve({ code, state, error })
|
})
|
||||||
}, 100)
|
}
|
||||||
|
|
||||||
return new Response(responseBody, {
|
return new Response("Not Found", { status: 404 })
|
||||||
status: 200,
|
},
|
||||||
headers: { "Content-Type": "text/html" },
|
})
|
||||||
})
|
|
||||||
}
|
const actualPort = server.port as number
|
||||||
|
|
||||||
return new Response("Not Found", { status: 404 })
|
const waitForCallback = (): Promise<CallbackResult> => {
|
||||||
},
|
return new Promise((resolve, reject) => {
|
||||||
})
|
resolveCallback = resolve
|
||||||
} catch (err) {
|
rejectCallback = reject
|
||||||
cleanup()
|
|
||||||
reject(
|
timeoutId = setTimeout(() => {
|
||||||
new Error(
|
cleanup()
|
||||||
`Failed to start callback server: ${err instanceof Error ? err.message : String(err)}`
|
reject(new Error("OAuth callback timeout"))
|
||||||
)
|
}, timeoutMs)
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
return {
|
||||||
|
port: actualPort,
|
||||||
|
waitForCallback,
|
||||||
|
close: cleanup,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform complete OAuth flow:
|
|
||||||
* 1. Start callback server
|
|
||||||
* 2. Build auth URL
|
|
||||||
* 3. Wait for callback
|
|
||||||
* 4. Exchange code for tokens
|
|
||||||
* 5. Fetch user info
|
|
||||||
*
|
|
||||||
* @param projectId - Optional GCP project ID
|
|
||||||
* @param openBrowser - Function to open URL in browser
|
|
||||||
* @param clientId - Optional custom client ID (defaults to ANTIGRAVITY_CLIENT_ID)
|
|
||||||
* @param clientSecret - Optional custom client secret (defaults to ANTIGRAVITY_CLIENT_SECRET)
|
|
||||||
* @returns Object with tokens and user info
|
|
||||||
*/
|
|
||||||
export async function performOAuthFlow(
|
export async function performOAuthFlow(
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
openBrowser?: (url: string) => Promise<void>,
|
openBrowser?: (url: string) => Promise<void>,
|
||||||
@@ -337,43 +326,36 @@ export async function performOAuthFlow(
|
|||||||
userInfo: AntigravityUserInfo
|
userInfo: AntigravityUserInfo
|
||||||
verifier: string
|
verifier: string
|
||||||
}> {
|
}> {
|
||||||
// Build auth URL first to get the verifier
|
const serverHandle = startCallbackServer()
|
||||||
const auth = await buildAuthURL(projectId, clientId)
|
|
||||||
|
|
||||||
// Start callback server
|
try {
|
||||||
const callbackPromise = startCallbackServer()
|
const auth = await buildAuthURL(projectId, clientId, serverHandle.port)
|
||||||
|
|
||||||
// Open browser (caller provides implementation)
|
if (openBrowser) {
|
||||||
if (openBrowser) {
|
await openBrowser(auth.url)
|
||||||
await openBrowser(auth.url)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for callback
|
const callback = await serverHandle.waitForCallback()
|
||||||
const callback = await callbackPromise
|
|
||||||
|
|
||||||
if (callback.error) {
|
if (callback.error) {
|
||||||
throw new Error(`OAuth error: ${callback.error}`)
|
throw new Error(`OAuth error: ${callback.error}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callback.code) {
|
if (!callback.code) {
|
||||||
throw new Error("No authorization code received")
|
throw new Error("No authorization code received")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify state and extract verifier
|
const state = decodeState(callback.state)
|
||||||
const state = decodeState(callback.state)
|
if (state.verifier !== auth.verifier) {
|
||||||
if (state.verifier !== auth.verifier) {
|
throw new Error("PKCE verifier mismatch - possible CSRF attack")
|
||||||
throw new Error("PKCE verifier mismatch - possible CSRF attack")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange code for tokens
|
const tokens = await exchangeCode(callback.code, auth.verifier, clientId, clientSecret, serverHandle.port)
|
||||||
const tokens = await exchangeCode(callback.code, auth.verifier, clientId, clientSecret)
|
const userInfo = await fetchUserInfo(tokens.access_token)
|
||||||
|
|
||||||
// Fetch user info
|
return { tokens, userInfo, verifier: auth.verifier }
|
||||||
const userInfo = await fetchUserInfo(tokens.access_token)
|
} catch (err) {
|
||||||
|
serverHandle.close()
|
||||||
return {
|
throw err
|
||||||
tokens,
|
|
||||||
userInfo,
|
|
||||||
verifier: auth.verifier,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,12 +99,24 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
auth: () => Promise<Auth>,
|
auth: () => Promise<Auth>,
|
||||||
provider: Provider
|
provider: Provider
|
||||||
): Promise<Record<string, unknown>> => {
|
): Promise<Record<string, unknown>> => {
|
||||||
// Check if current auth is OAuth type
|
|
||||||
const currentAuth = await auth()
|
const currentAuth = await auth()
|
||||||
|
|
||||||
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
|
console.log("[antigravity-plugin] loader called")
|
||||||
|
console.log("[antigravity-plugin] auth type:", currentAuth?.type)
|
||||||
|
console.log("[antigravity-plugin] auth keys:", Object.keys(currentAuth || {}))
|
||||||
|
}
|
||||||
|
|
||||||
if (!isOAuthAuth(currentAuth)) {
|
if (!isOAuthAuth(currentAuth)) {
|
||||||
// Not OAuth auth, return empty (fallback to default fetch)
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
|
console.log("[antigravity-plugin] NOT OAuth auth, returning empty")
|
||||||
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
|
console.log("[antigravity-plugin] OAuth auth detected, creating custom fetch")
|
||||||
|
}
|
||||||
|
|
||||||
cachedClientId =
|
cachedClientId =
|
||||||
(provider.options?.clientId as string) || ANTIGRAVITY_CLIENT_ID
|
(provider.options?.clientId as string) || ANTIGRAVITY_CLIENT_ID
|
||||||
@@ -167,6 +179,7 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
fetch: antigravityFetch,
|
fetch: antigravityFetch,
|
||||||
|
apiKey: "antigravity-oauth",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -188,10 +201,8 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
* @returns Authorization result with URL and callback
|
* @returns Authorization result with URL and callback
|
||||||
*/
|
*/
|
||||||
authorize: async (): Promise<AuthOuathResult> => {
|
authorize: async (): Promise<AuthOuathResult> => {
|
||||||
const { url, verifier } = await buildAuthURL(undefined, cachedClientId)
|
const serverHandle = startCallbackServer()
|
||||||
|
const { url, verifier } = await buildAuthURL(undefined, cachedClientId, serverHandle.port)
|
||||||
// Start local callback server to receive OAuth callback
|
|
||||||
const callbackPromise = startCallbackServer()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url,
|
url,
|
||||||
@@ -199,35 +210,24 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
"Complete the sign-in in your browser. We'll automatically detect when you're done.",
|
"Complete the sign-in in your browser. We'll automatically detect when you're done.",
|
||||||
method: "auto",
|
method: "auto",
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function invoked when OAuth redirect is received.
|
|
||||||
* Exchanges code for tokens and fetches project context.
|
|
||||||
*/
|
|
||||||
callback: async () => {
|
callback: async () => {
|
||||||
try {
|
try {
|
||||||
// Wait for OAuth callback
|
const result = await serverHandle.waitForCallback()
|
||||||
const result = await callbackPromise
|
|
||||||
|
|
||||||
// Check for errors
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
console.error(
|
console.error(`[antigravity-plugin] OAuth error: ${result.error}`)
|
||||||
`[antigravity-plugin] OAuth error: ${result.error}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return { type: "failed" as const }
|
return { type: "failed" as const }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.code) {
|
if (!result.code) {
|
||||||
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
console.error(
|
console.error("[antigravity-plugin] No authorization code received")
|
||||||
"[antigravity-plugin] No authorization code received"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return { type: "failed" as const }
|
return { type: "failed" as const }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify state and extract original verifier
|
|
||||||
const state = decodeState(result.state)
|
const state = decodeState(result.state)
|
||||||
if (state.verifier !== verifier) {
|
if (state.verifier !== verifier) {
|
||||||
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
@@ -236,27 +236,19 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
return { type: "failed" as const }
|
return { type: "failed" as const }
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokens = await exchangeCode(result.code, verifier, cachedClientId, cachedClientSecret)
|
const tokens = await exchangeCode(result.code, verifier, cachedClientId, cachedClientSecret, serverHandle.port)
|
||||||
|
|
||||||
// Fetch user info (optional, for logging)
|
|
||||||
try {
|
try {
|
||||||
const userInfo = await fetchUserInfo(tokens.access_token)
|
const userInfo = await fetchUserInfo(tokens.access_token)
|
||||||
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
console.log(
|
console.log(`[antigravity-plugin] Authenticated as: ${userInfo.email}`)
|
||||||
`[antigravity-plugin] Authenticated as: ${userInfo.email}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// User info is optional, continue without it
|
// User info is optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch project context for Antigravity API
|
const projectContext = await fetchProjectContext(tokens.access_token)
|
||||||
const projectContext = await fetchProjectContext(
|
|
||||||
tokens.access_token
|
|
||||||
)
|
|
||||||
|
|
||||||
// Format refresh token with project info for storage
|
|
||||||
// Format: refreshToken|projectId|managedProjectId
|
|
||||||
const formattedRefresh = formatTokenForStorage(
|
const formattedRefresh = formatTokenForStorage(
|
||||||
tokens.refresh_token,
|
tokens.refresh_token,
|
||||||
projectContext.cloudaicompanionProject || "",
|
projectContext.cloudaicompanionProject || "",
|
||||||
@@ -270,6 +262,7 @@ export async function createGoogleAntigravityAuthPlugin({
|
|||||||
expires: Date.now() + tokens.expires_in * 1000,
|
expires: Date.now() + tokens.expires_in * 1000,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
serverHandle.close()
|
||||||
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
||||||
console.error(
|
console.error(
|
||||||
`[antigravity-plugin] OAuth flow failed: ${
|
`[antigravity-plugin] OAuth flow failed: ${
|
||||||
|
|||||||
@@ -128,30 +128,32 @@ export function getDefaultEndpoint(): string {
|
|||||||
return ANTIGRAVITY_ENDPOINT_FALLBACKS[0]
|
return ANTIGRAVITY_ENDPOINT_FALLBACKS[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function generateRequestId(): string {
|
||||||
* Wrap a request body in Antigravity format.
|
return `agent-${crypto.randomUUID()}`
|
||||||
* Creates a new object without modifying the original.
|
}
|
||||||
*
|
|
||||||
* @param body - Original request payload
|
function generateSessionId(): string {
|
||||||
* @param projectId - GCP project ID
|
const n = Math.floor(Math.random() * 9_000_000_000_000_000_000)
|
||||||
* @param modelName - Model identifier
|
return `-${n}`
|
||||||
* @returns Wrapped request body in Antigravity format
|
}
|
||||||
*/
|
|
||||||
export function wrapRequestBody(
|
export function wrapRequestBody(
|
||||||
body: Record<string, unknown>,
|
body: Record<string, unknown>,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
modelName: string
|
modelName: string
|
||||||
): AntigravityRequestBody {
|
): AntigravityRequestBody {
|
||||||
// Clone the body to avoid mutation
|
|
||||||
const requestPayload = { ...body }
|
const requestPayload = { ...body }
|
||||||
|
|
||||||
// Remove model from inner request (it's in wrapper)
|
|
||||||
delete requestPayload.model
|
delete requestPayload.model
|
||||||
|
|
||||||
return {
|
return {
|
||||||
project: projectId,
|
project: projectId,
|
||||||
model: modelName,
|
model: modelName,
|
||||||
request: requestPayload,
|
userAgent: "antigravity",
|
||||||
|
requestId: generateRequestId(),
|
||||||
|
request: {
|
||||||
|
...requestPayload,
|
||||||
|
sessionId: generateSessionId(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ export interface AntigravityRequestBody {
|
|||||||
project: string
|
project: string
|
||||||
/** Model identifier (e.g., "gemini-3-pro-preview") */
|
/** Model identifier (e.g., "gemini-3-pro-preview") */
|
||||||
model: string
|
model: string
|
||||||
|
/** User agent identifier */
|
||||||
|
userAgent: string
|
||||||
|
/** Unique request ID */
|
||||||
|
requestId: string
|
||||||
/** The actual request payload */
|
/** The actual request payload */
|
||||||
request: Record<string, unknown>
|
request: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/google-auth.ts
Normal file
8
src/google-auth.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { Plugin } from "@opencode-ai/plugin"
|
||||||
|
import { createGoogleAntigravityAuthPlugin } from "./auth/antigravity"
|
||||||
|
|
||||||
|
const GoogleAntigravityAuthPlugin: Plugin = async (ctx) => {
|
||||||
|
return createGoogleAntigravityAuthPlugin(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GoogleAntigravityAuthPlugin
|
||||||
Reference in New Issue
Block a user