feat(cdp-bridge): improve antigravity client and shared protobuf definitions

Updates to the CDP bridge and shared protocol layer:

- infra/cdp-bridge/src/cdp_controller.js: Enhanced CDP session management
- infra/cdp-bridge/src/services/antigravity_client.js: Improved Antigravity
  WebSocket client with reconnection and error handling
- shared/buf.connect.gen.yaml / shared/buf.es.gen.yaml: Buf code generation
  configuration updates
- shared/src/proto/antigravity_connect.ts / antigravity_pb.ts: Updated
  Connect-RPC protobuf definitions for the Antigravity protocol
This commit is contained in:
AI Agent 2026-06-07 21:27:34 +01:00
parent 3ab9284d82
commit 3641b7e575
7 changed files with 144 additions and 5 deletions

View file

@ -0,0 +1,87 @@
# Antigravity Panel Authentication Fix
## Problem
The Antigravity IDE/LS was updated and now requires **Google OAuth authentication**. The previous CDP-based integration is broken because:
1. The CDP Bridge (`cdp_controller.js`) gets stuck on a Google login screen with no handling
2. The gRPC client (`antigravity_client.js`) sends no CSRF/auth tokens
3. The Dirac native bridge has `inject_oauth_token()` implemented but was never called from TypeScript
4. `Antigravity-Tools-LS` exists as a submodule and handles OAuth but wasn't integrated
## Changes Made
### 1. CDP Bridge — OAuth Detection & CSRF Support
- **`src/cdp_controller.js`**: Added `isOAuthScreen()` detection that checks for Google login URLs and DOM elements. `connect()` and `getStatus()` now throw/report descriptive errors when authentication is required.
- **`src/services/antigravity_client.js`**: Added `AG_CSRF_TOKEN` environment variable support and a ConnectRPC interceptor that injects the `x-codeium-csrf-token` header on every gRPC request.
### 2. VS Code Extension — Dirac Native Integration
- **`package.json`**: Added two new settings:
- `aurelio.antigravity.oauthToken` — object with `accessToken`, `refreshToken`, `expiry`
- `aurelio.antigravity.lsBinaryPath` — absolute path to the `language_server` binary
- **`src/webview/controlCenterPanel.ts`**:
- Added `_getDiracClient()` helper that reuses the ChatPanel's Dirac client or creates a standalone one
- Added `_agNativeInfo` field to track spawned LS port/CSRF token
- `antigravityGrpcConnect` (native mode): Automatically spawns the LS via `dirac.startSelfHosted()` and injects the OAuth token via `dirac.injectOAuthToken()`
- `antigravitySendPrompt` / `antigravityQuickAction` (native mode): Validate that the LS is spawned before sending prompts
- **`src/core/diracClient.ts`**: Fixed parameter name mismatch (`ls_binary_path` → `binary_path`) to match the Rust backend.
### 3. Aurelio-Web — Dirac Fallback
- **`server/services/messageDispatcher.ts`**:
- Reads `ANTIGRAVITY_LS_BINARY`, `ANTIGRAVITY_OAUTH_ACCESS_TOKEN`, `ANTIGRAVITY_OAUTH_REFRESH_TOKEN`, `ANTIGRAVITY_OAUTH_EXPIRY` from environment variables
- Added `tryDiracPrompt()` helper that spawns the LS via Dirac and falls back to the CDP bridge on failure
- `antigravitySendPrompt` and `antigravityQuickAction` now try Dirac first when `ANTIGRAVITY_LS_BINARY` is configured
- Added `antigravityNativeConnect` handler to explicitly spawn the LS via Dirac
- **`server/services/diracClient.ts`**: Fixed parameter name mismatch (`ls_binary_path` → `binary_path`)
## Deployment Notes
### For CT 212 (Proxmox CDP Bridge)
If the CDP bridge continues to hit the OAuth wall, deploy **Antigravity-Tools-LS** as a sidecar on CT 212:
```bash
# On CT 212
docker run -d \
--name antigravity-ls \
-p 5188:5188 \
-e PORT=5188 \
-e RUST_LOG=info \
-v ~/.antigravity-ls-data:/root/.antigravity_tools_ls \
lbjlaq/antigravity-tools-ls:latest
```
Then configure the CDP bridge to use the sidecar's gRPC endpoint instead of the headless IDE:
```bash
export AG_LS_HOST=127.0.0.1
export AG_LS_PORT=5188
export AG_CSRF_TOKEN=<csrf-token-from-sidecar>
```
### For Aurelio-Web Server
To enable native Dirac mode on the web backend, set the environment variables before starting the server:
```bash
export ANTIGRAVITY_LS_BINARY=/usr/local/bin/language_server_linux_x64
export ANTIGRAVITY_OAUTH_ACCESS_TOKEN=<your-google-access-token>
export ANTIGRAVITY_OAUTH_REFRESH_TOKEN=<your-google-refresh-token>
export ANTIGRAVITY_OAUTH_EXPIRY=2026-06-04T12:00:00Z
```
### For VS Code Extension Users
1. Set `aurelio.antigravity.mode` to `"native"`
2. Set `aurelio.antigravity.lsBinaryPath` to your `language_server` binary path (or leave empty for auto-detect)
3. Set `aurelio.antigravity.oauthToken.accessToken` and `refreshToken` from your Google OAuth session
4. Click **Connect** in the Control Center's Antigravidade panel
## Preserved Functionality
- Non-Antigravity features (MCP, Brain, Vertex AI, Jules, etc.) are untouched
- The `auto` and `cdp` modes in the VS Code extension continue to work as before
- The CDP bridge REST API remains available for non-authenticated use cases

View file

@ -16,15 +16,49 @@ let browser = null;
/** @type {import('puppeteer-core').Page | null} */
let workbenchPage = null;
/**
* Detect if the Antigravity IDE is stuck on an OAuth / Google login screen.
* Returns true if authentication is required before the IDE can be used.
*/
async function isOAuthScreen(page) {
try {
const url = page.url();
if (url.includes('accounts.google.com') || url.includes('oauth') || url.includes('login')) {
return true;
}
// Check for login-related DOM elements
const hasLoginElements = await page.evaluate(() => {
const selectors = [
'input[type="email"]',
'input[type="password"]',
'button:has-text("Sign in")',
'button:has-text("Next")',
'[data-testid="google-sign-in"]',
'.auth-login-form',
'.oauth-container',
];
return selectors.some(sel => document.querySelector(sel) !== null);
});
return hasLoginElements;
} catch {
return false;
}
}
/**
* Connect to the Antigravity IDE via CDP.
* Establishes a Puppeteer session using the CDP endpoint and discovers the workbench page.
* Throws if the IDE requires OAuth authentication.
*/
export async function connect() {
if (browser && workbenchPage) {
try {
// Test if connection is still alive
await workbenchPage.evaluate(() => true);
// Re-check OAuth barrier on reconnect — token may have expired
if (await isOAuthScreen(workbenchPage)) {
throw new Error('[CDP] OAuth authentication required. The Antigravity IDE is on a Google login screen. Please inject a valid OAuth token or log in manually.');
}
return workbenchPage;
} catch {
// Connection lost, reconnect
@ -50,6 +84,11 @@ export async function connect() {
throw new Error('[CDP] Could not acquire workbench page handle');
}
// OAuth barrier detection — Antigravity now requires Google OAuth
if (await isOAuthScreen(workbenchPage)) {
throw new Error('[CDP] OAuth authentication required. The Antigravity IDE is on a Google login screen. Please inject a valid OAuth token or log in manually.');
}
console.log('[CDP] Connected successfully');
return workbenchPage;
}
@ -316,6 +355,7 @@ export async function getCurrentModel() {
/**
* Get connection status info.
* Reports OAuth barrier when the IDE requires authentication.
*/
export async function getStatus() {
try {
@ -330,9 +370,11 @@ export async function getStatus() {
timestamp: new Date().toISOString(),
};
} catch (err) {
const isOAuthError = err.message.includes('OAuth');
return {
connected: false,
error: err.message,
oauthRequired: isOAuthError,
timestamp: new Date().toISOString(),
};
}

View file

@ -14,6 +14,7 @@ import { createGrpcTransport } from '@connectrpc/connect-node';
// --- Configuration ---
const LS_HOST = process.env.AG_LS_HOST || '127.0.0.1';
const LS_PORT = process.env.AG_LS_PORT || '3000';
const CSRF_TOKEN = process.env.AG_CSRF_TOKEN || '';
/**
* Service definition matching the generated proto.
@ -72,6 +73,15 @@ function getClient() {
const transport = createGrpcTransport({
baseUrl,
httpVersion: '2',
interceptors: [
(next) => async (req) => {
// Inject CSRF token for Antigravity Language Server authentication
if (CSRF_TOKEN) {
req.header.set('x-codeium-csrf-token', CSRF_TOKEN);
}
return await next(req);
},
],
});
_client = createClient(AntigravityLanguageServerService, transport);

View file

@ -4,4 +4,4 @@ plugins:
out: src/proto
opt:
- target=ts
- import_extension=js
- import_extension=.js

View file

@ -4,4 +4,4 @@ plugins:
out: src/proto
opt:
- target=ts
- import_extension=js
- import_extension=.js

View file

@ -1,9 +1,9 @@
// @generated by protoc-gen-connect-es v1.7.0 with parameter "target=ts,import_extension=js"
// @generated by protoc-gen-connect-es v1.7.0 with parameter "target=ts,import_extension=.js"
// @generated from file antigravity.proto (package antigravity.language_server_pb, syntax proto3)
/* eslint-disable */
// @ts-nocheck
import { AntigravityEmpty, AntigravityGetLoadCodeAssistResponse, AntigravityGetWorkspaceInfosResponse, AntigravityInitializeCascadePanelStateRequest, AntigravityInitializeCascadePanelStateResponse, AntigravitySendAgentMessageRequest, AntigravitySendAgentMessageResponse, AntigravityStartCascadeRequest, AntigravityStartCascadeResponse, AntigravityStreamReactiveUpdatesRequest, AntigravityStreamReactiveUpdatesResponse } from "./antigravity_pbjs";
import { AntigravityEmpty, AntigravityGetLoadCodeAssistResponse, AntigravityGetWorkspaceInfosResponse, AntigravityInitializeCascadePanelStateRequest, AntigravityInitializeCascadePanelStateResponse, AntigravitySendAgentMessageRequest, AntigravitySendAgentMessageResponse, AntigravityStartCascadeRequest, AntigravityStartCascadeResponse, AntigravityStreamReactiveUpdatesRequest, AntigravityStreamReactiveUpdatesResponse } from "./antigravity_pb.js";
import { MethodKind } from "@bufbuild/protobuf";
/**

View file

@ -1,4 +1,4 @@
// @generated by protoc-gen-es v1.10.0 with parameter "target=ts,import_extension=js"
// @generated by protoc-gen-es v1.10.0 with parameter "target=ts,import_extension=.js"
// @generated from file antigravity.proto (package antigravity.language_server_pb, syntax proto3)
/* eslint-disable */
// @ts-nocheck