/** * Main SDK entry point. * * Provides a unified interface to Antigravity's agent system * via verified transport layer (CommandBridge + StateBridge + EventMonitor). * * @module AntigravitySDK * * @example * ```typescript * import { AntigravitySDK } from 'antigravity-sdk'; * * export function activate(context: vscode.ExtensionContext) { * const sdk = new AntigravitySDK(context); * await sdk.initialize(); * * // List conversations * const sessions = await sdk.cascade.getSessions(); * console.log(`${sessions.length} conversations`); * * // Read preferences (all 16 sentinel values) * const prefs = await sdk.cascade.getPreferences(); * console.log('Terminal policy:', prefs.terminalExecutionPolicy); * * // Monitor for new conversations * sdk.monitor.onNewConversation(() => { * console.log('New conversation detected!'); * }); * sdk.monitor.start(3000); * * // Clean up * context.subscriptions.push(sdk); * } * ``` */ import * as vscode from 'vscode'; import { DisposableStore, IDisposable } from './core/disposable'; import { Logger, LogLevel } from './core/logger'; import { AntigravityNotFoundError } from './core/errors'; import { CommandBridge } from './transport/command-bridge'; import { StateBridge } from './transport/state-bridge'; import { EventMonitor } from './transport/event-monitor'; import { LSBridge } from './transport/ls-bridge'; import { CascadeManager } from './cascade/cascade-manager'; import { IntegrationManager } from './integration/integration-manager'; const log = new Logger('SDK'); /** * SDK initialization options. */ export interface ISDKOptions { /** Enable debug logging */ debug?: boolean; } /** * The main Antigravity SDK class. * * Provides access to: * - `commands` — Execute Antigravity internal commands * - `state` — Read agent preferences and state from USS * - `cascade` — Manage Cascade conversations, send messages, read preferences * - `monitor` — Watch for state changes (new conversations, preference updates) * * @example * ```typescript * const sdk = new AntigravitySDK(context); * await sdk.initialize(); * const sessions = await sdk.cascade.getSessions(); * ``` */ export class AntigravitySDK implements IDisposable { private readonly _disposables = new DisposableStore(); private _initialized = false; /** Command bridge for executing Antigravity commands */ public readonly commands: CommandBridge; /** State bridge for reading USS data */ public readonly state: StateBridge; /** Cascade manager for conversations, preferences, diagnostics */ public readonly cascade: CascadeManager; /** Event monitor for watching state changes */ public readonly monitor: EventMonitor; /** Integration manager for Agent View UI customization */ public readonly integration: IntegrationManager; /** * Language Server bridge for headless cascade operations. * Use this for background cascade creation without UI switching. * * @example * ```typescript * const id = await sdk.ls.createCascade({ text: 'Analyze coverage' }); * await sdk.ls.sendMessage({ cascadeId: id, text: 'Focus on tests' }); * await sdk.ls.focusCascade(id); // Only when ready to show * ``` */ public readonly ls: LSBridge; /** * Create a new Antigravity SDK instance. * * @param context - VS Code extension context * @param options - SDK options */ constructor( private readonly _context: vscode.ExtensionContext, options?: ISDKOptions, ) { if (options?.debug) { Logger.setLevel(LogLevel.Debug); } // Derive namespace from extension ID for file isolation // e.g. 'kanezal.better-antigravity' -> 'kanezal-better-antigravity' const namespace = this._context.extension.id.replace(/\./g, '-'); this.commands = this._disposables.add(new CommandBridge()); this.state = this._disposables.add(new StateBridge()); this.cascade = this._disposables.add(new CascadeManager(this.commands, this.state)); this.monitor = this._disposables.add(new EventMonitor(this.state)); this.integration = this._disposables.add(new IntegrationManager(namespace)); this.ls = new LSBridge( (cmd: string, ...args: any[]) => Promise.resolve(vscode.commands.executeCommand(cmd, ...args)) ); log.info(`SDK created (namespace: ${namespace})`); } /** * Initialize the SDK and verify Antigravity is running. * * Call this before using any SDK features. * * @throws {AntigravityNotFoundError} If Antigravity is not detected */ async initialize(): Promise { if (this._initialized) { return; } log.info('Initializing SDK...'); // Verify we're running inside Antigravity const isAntigravity = await this._detectAntigravity(); if (!isAntigravity) { throw new AntigravityNotFoundError(); } // Initialize state bridge (opens state.vscdb via sql.js) await this.state.initialize(); // Initialize cascade manager (loads session list) await this.cascade.initialize(); // Initialize LS bridge (discovers Language Server port + CSRF token) const lsOk = await this.ls.initialize(); if (lsOk) { log.info(`LS bridge ready on port ${this.ls.port} (csrf: ${this.ls.hasCsrfToken ? 'ok' : 'missing'})`); } else { log.warn('LS bridge not available — use sdk.ls.setConnection(port, csrfToken) or command fallback'); } // Refresh integration heartbeat (so renderer script knows extension is active) this.integration.signalActive(); this._initialized = true; log.info('SDK initialized successfully'); } /** * Check if the SDK has been initialized. */ get isInitialized(): boolean { return this._initialized; } /** * Get the SDK version. */ get version(): string { try { return require('../package.json').version; } catch { return 'unknown'; } } /** * Detect if we're running inside Antigravity IDE. */ private async _detectAntigravity(): Promise { try { // Check for Antigravity-specific commands (VERIFIED naming) const commands = await this.commands.getAntigravityCommands(); const hasAgentPanel = commands.includes('antigravity.agentPanel.open'); if (hasAgentPanel) { log.debug(`Detected Antigravity (${commands.length} commands)`); return true; } // Fallback: check env const appName = vscode.env.appName; if (appName?.toLowerCase().includes('antigravity')) { log.debug(`Detected Antigravity via appName: ${appName}`); return true; } return false; } catch { return false; } } /** * Dispose of the SDK and all its resources. */ dispose(): void { log.info('Disposing SDK'); this._disposables.dispose(); } }