Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AntigravityCLIOAuthPlugin } from "./src/plugin";

export {
AntigravityCLIOAuthPlugin,
GoogleOAuthPlugin,
Expand All @@ -12,3 +14,17 @@ export type {
AntigravityAuthorization,
AntigravityTokenExchangeResult,
} from "./src/antigravity/oauth";

const defaultPlugin = {
id: "antigravity-auth",
setup: async (input: any) => {
const patchedInput = {
...input,
client: input.app || input.client || {},
directory: input.location?.directory || input.directory || process.cwd(),
};
return AntigravityCLIOAuthPlugin(patchedInput);
},
};

export default defaultPlugin;
5 changes: 4 additions & 1 deletion src/hooks/auto-update-checker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function createAutoUpdateCheckerHook(

hasChecked = true;

setTimeout(() => {
const timer = setTimeout(() => {
const localDevVersion = getLocalDevVersion(directory);

if (localDevVersion) {
Expand All @@ -62,6 +62,9 @@ export function createAutoUpdateCheckerHook(
logAutoUpdate(`Background update check failed: ${err}`);
});
}, 0);
if (typeof timer.unref === "function") {
timer.unref();
}
},
};
}
Expand Down
8 changes: 5 additions & 3 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,9 @@ function sleep(ms: number, signal?: AbortSignal | null): Promise<void> {
export const createAntigravityPlugin = (providerId: string) => async (
{ client, directory }: PluginContext,
): Promise<PluginResult> => {
const targetDir = directory || process.cwd();
// Load configuration from files and environment variables
const config = loadConfig(directory);
const config = loadConfig(targetDir);
initRuntimeConfig(config);

// Cached getAuth function for tool access
Expand Down Expand Up @@ -1452,8 +1453,9 @@ export const createAntigravityPlugin = (providerId: string) => async (
return {
apiKey: "",
async fetch(input, init) {
const originalFetch = (provider as any)?.fetch ?? globalThis.fetch;
if (!isGenerativeLanguageRequest(input)) {
return fetch(input, init);
return originalFetch(input, init);
}

const latestAuth = await getAuth();
Expand Down Expand Up @@ -2544,7 +2546,7 @@ export const createAntigravityPlugin = (providerId: string) => async (
);

// CLI flow (`opencode auth login`) passes an inputs object.
if (inputs) {
if (inputs && process.stdout?.isTTY && process.stdin?.isTTY) {
const accounts: Array<Extract<AntigravityTokenExchangeResult, { type: "success" }>> = [];
const noBrowser = inputs.noBrowser === "true" || inputs["no-browser"] === "true";
const useManualMode = noBrowser || shouldSkipLocalServer();
Expand Down
6 changes: 6 additions & 0 deletions src/plugin/cache/signature-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,11 +430,17 @@ export class SignatureCache {
this.saveToDisk();
}
}, this.writeIntervalMs);
if (this.writeTimer && typeof this.writeTimer.unref === "function") {
this.writeTimer.unref();
}

// Periodic memory cleanup (every 30 minutes)
this.cleanupTimer = setInterval(() => {
this.cleanupExpired();
}, 30 * 60 * 1000);
if (this.cleanupTimer && typeof this.cleanupTimer.unref === "function") {
this.cleanupTimer.unref();
}
}

/**
Expand Down
17 changes: 11 additions & 6 deletions src/plugin/config/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export function getUserConfigPath(): string {
/**
* Get the project-level config file path.
*/
export function getProjectConfigPath(directory: string): string {
export function getProjectConfigPath(directory?: string): string | null {
if (!directory) return null;
return join(directory, ".opencode", "antigravity.json");
}

Expand Down Expand Up @@ -118,7 +119,7 @@ function mergeConfigs(
* @param directory - The project directory (for project-level config)
* @returns Fully resolved configuration
*/
export function loadConfig(directory: string): AntigravityConfig {
export function loadConfig(directory?: string): AntigravityConfig {
// Start with defaults
let config: AntigravityConfig = { ...DEFAULT_CONFIG };

Expand All @@ -130,10 +131,14 @@ export function loadConfig(directory: string): AntigravityConfig {
}

// Load project config file (if exists) - overrides user config
const projectConfigPath = getProjectConfigPath(directory);
const projectConfig = loadConfigFile(projectConfigPath);
if (projectConfig) {
config = mergeConfigs(config, projectConfig);
if (directory) {
const projectConfigPath = getProjectConfigPath(directory);
if (projectConfigPath) {
const projectConfig = loadConfigFile(projectConfigPath);
if (projectConfig) {
config = mergeConfigs(config, projectConfig);
}
}
}

return config;
Expand Down
8 changes: 7 additions & 1 deletion src/plugin/refresh-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export class ProactiveRefreshQueue {
});

// Run initial check after a short delay (let things settle)
setTimeout(() => {
const initialTimer = setTimeout(() => {
if (this.state.isRunning) {
this.runRefreshCheck().catch((error) => {
log.error("Initial check failed", {
Expand All @@ -257,6 +257,9 @@ export class ProactiveRefreshQueue {
});
}
}, 5000);
if (typeof initialTimer.unref === "function") {
initialTimer.unref();
}

// Set up periodic checks
this.state.intervalHandle = setInterval(() => {
Expand All @@ -266,6 +269,9 @@ export class ProactiveRefreshQueue {
});
});
}, intervalMs);
if (this.state.intervalHandle && typeof this.state.intervalHandle.unref === "function") {
this.state.intervalHandle.unref();
}
}

/**
Expand Down
16 changes: 13 additions & 3 deletions src/plugin/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,8 +753,17 @@ const STREAM_ACTION = "streamGenerateContent";
/**
* Detects requests headed to the Google Generative Language API so we can intercept them.
*/
export function isGenerativeLanguageRequest(input: RequestInfo): input is string {
return typeof input === "string" && input.includes("generativelanguage.googleapis.com");
export function isGenerativeLanguageRequest(input: RequestInfo | URL): boolean {
if (typeof input === "string") {
return input.includes("generativelanguage.googleapis.com");
}
if (input instanceof URL) {
return input.href.includes("generativelanguage.googleapis.com");
}
if (typeof input === "object" && input !== null && "url" in input) {
return typeof (input as Request).url === "string" && (input as Request).url.includes("generativelanguage.googleapis.com");
}
return false;
}

/**
Expand Down Expand Up @@ -822,7 +831,8 @@ export function prepareAntigravityRequest(
// that are not required for Antigravity/Gemini CLI OAuth requests.
headers.delete("x-goog-user-project");

const match = input.match(/\/models\/([^:]+):(\w+)/);
const inputUrl = typeof input === "string" ? input : (input instanceof URL ? input.href : (input as Request).url);
const match = inputUrl.match(/\/models\/([^:]+):(\w+)/);
if (!match) {
return {
request: input,
Expand Down