From 4bb72921ae22534f09b9b93d006f657ba11bb457 Mon Sep 17 00:00:00 2001 From: CD Date: Sun, 8 Mar 2026 00:45:07 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20embed=20antigravity-sdk=20source=20?= =?UTF-8?q?=E2=80=94=20zero=20npm=20dependencies=20(45KB=20VSIX)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extension/.vscodeignore | 6 + extension/gravity-bridge-0.2.0.vsix | Bin 12502 -> 46431 bytes extension/out/extension.js | 4 +- extension/out/extension.js.map | 2 +- extension/package.json | 5 +- extension/src/extension.ts | 4 +- extension/src/sdk/README.md | 336 +++ extension/src/sdk/index.d.ts | 2297 +++++++++++++++ extension/src/sdk/index.js | 4014 +++++++++++++++++++++++++++ 9 files changed, 6659 insertions(+), 9 deletions(-) create mode 100644 extension/.vscodeignore create mode 100644 extension/src/sdk/README.md create mode 100644 extension/src/sdk/index.d.ts create mode 100644 extension/src/sdk/index.js diff --git a/extension/.vscodeignore b/extension/.vscodeignore new file mode 100644 index 0000000..759cf76 --- /dev/null +++ b/extension/.vscodeignore @@ -0,0 +1,6 @@ +src/** +node_modules/** +*.ts +!out/** +tsconfig.json +.gitignore diff --git a/extension/gravity-bridge-0.2.0.vsix b/extension/gravity-bridge-0.2.0.vsix index 91ddf873756cb0540f7e367c63847d19af852a10..b6cb9db1c45819807fb96939608c086734846fdd 100644 GIT binary patch delta 44892 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 Aq5uE@ delta 10714 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 { try { - const sdkModule = require('antigravity-sdk'); + const sdkModule = require('./sdk/index'); AntigravitySDK = sdkModule.AntigravitySDK; } catch (err: any) { console.log(`Gravity Bridge: antigravity-sdk load failed: ${err.message}`); diff --git a/extension/src/sdk/README.md b/extension/src/sdk/README.md new file mode 100644 index 0000000..cffbadc --- /dev/null +++ b/extension/src/sdk/README.md @@ -0,0 +1,336 @@ +
+ +# Antigravity SDK + +**Community SDK for building extensions for [Antigravity IDE](https://antigravity.dev)** + +[![npm](https://img.shields.io/npm/v/antigravity-sdk)](https://www.npmjs.com/package/antigravity-sdk) +[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) + +*Build powerful extensions that work alongside Antigravity's AI agent.* + +
+ +--- + +## What is this? + +A TypeScript SDK for building **VS Code extensions** that extend Antigravity IDE. It gives you programmatic access to the agent's conversations, preferences, step control, real-time activity monitoring, and a declarative API for integrating custom UI directly into the Agent View — all through Antigravity's own extension protocols. + +> [!IMPORTANT] +> This SDK is designed **exclusively** for building Antigravity extensions. It is **not** a tool for integrating Antigravity with third-party applications, extracting data, or proxying requests. See [Compliance](#compliance). + +--- + +## Quick Start + +```bash +npm install antigravity-sdk +``` + +```typescript +import { AntigravitySDK } from 'antigravity-sdk'; + +export async function activate(context: vscode.ExtensionContext) { + const sdk = new AntigravitySDK(context); + await sdk.initialize(); + + // List conversations with real titles + const sessions = await sdk.cascade.getSessions(); + console.log(`${sessions.length} conversations`); + + // Read all 16 agent preferences + const prefs = await sdk.cascade.getPreferences(); + console.log('Terminal policy:', prefs.terminalExecutionPolicy); + + // Monitor agent activity in real time + sdk.monitor.onStepCountChanged((e) => { + console.log(`${e.title}: +${e.delta} steps`); + }); + sdk.monitor.onActiveSessionChanged((e) => { + console.log(`Switched to: ${e.title}`); + }); + sdk.monitor.start(); + + // Accept/reject agent steps programmatically + await sdk.cascade.acceptStep(); + await sdk.cascade.acceptTerminalCommand(); + + context.subscriptions.push(sdk); +} +``` + +--- + +## Features + +### Agent View UI Integration + +The SDK provides **9 integration points** in the Agent View panel — add buttons, metadata, badges, menu items, and interactive elements with a fluent, declarative API. Everything is theme-aware and survives Antigravity updates via auto-repair. + +```typescript +import { IntegrationManager, IntegrationPoint } from 'antigravity-sdk'; + +const ui = new IntegrationManager(); + +// Fluent API — chain calls +ui.addTopBarButton('stats', '📊', 'Show Stats', { + title: 'Session Stats', + rows: [{ key: 'Steps:', value: '42' }], + }) + .addInputButton('tokens', '🔢', 'Token Counter') + .addTurnMetadata('meta', ['turnNumber', 'userCharCount', 'aiCharCount', 'codeBlocks']) + .addUserBadges('badges', 'charCount') + .addBotAction('inspect', '🔍', 'Inspect Response') + .addDropdownItem('export', 'Export Chat', '📋') + .addTitleInteraction('title', 'dblclick', 'Double-click to bookmark'); + +await ui.install(); +ui.enableAutoRepair(); // Survives Antigravity updates +``` + +| Integration Point | Location | Use Cases | +|-------------------|----------|-----------| +| `TOP_BAR` | Header icon bar | Session overview, navigation | +| `TOP_RIGHT` | Before close button | Status indicators, quick toggle | +| `INPUT_AREA` | Next to send button | Token counter, prompt templates | +| `BOTTOM_ICONS` | Bottom icon row | Mode switches, quick actions | +| `TURN_METADATA` | Inside each turn | Character count, code block stats, turn numbers | +| `USER_BADGE` | User message bubble | Message length indicator | +| `BOT_ACTION` | Next to Good/Bad | Response analysis, copy actions | +| `DROPDOWN_MENU` | 3-dot overflow menu | Export, settings, debug tools | +| `CHAT_TITLE` | Conversation title | Rename, bookmark on interaction | + +> [!NOTE] +> The integration script runs in the renderer process, independent of the extension. The SDK uses a **heartbeat mechanism** to prevent orphaned integrations: `sdk.initialize()` refreshes a timestamp marker, and the script silently exits if the marker is stale (48h). Disabling your extension will automatically stop the integration on the next IDE restart after the grace period. + +### Conversation Management + +Full control over Cascade conversations — list, create, switch, send messages, and manage agent steps. + +```typescript +// List sessions with titles, step counts, timestamps +const sessions = await sdk.cascade.getSessions(); + +// Switch to a conversation +await sdk.cascade.focusSession(sessions[0].id); + +// Send a message to the active chat +await sdk.cascade.sendPrompt('Analyze this file'); + +// Create a background conversation +const id = await sdk.cascade.createBackgroundSession('Run tests quietly'); +``` + +### Real-Time Event Monitoring + +Watch for state changes as they happen — new conversations, step progress, session switches, preference updates. + +```typescript +// Agent made progress (added steps) +sdk.monitor.onStepCountChanged((e) => { + statusBar.text = `${e.title}: step ${e.newCount}`; +}); + +// User switched to a different conversation +sdk.monitor.onActiveSessionChanged((e) => { + console.log(`Now viewing: ${e.title}`); +}); + +// New conversation created +sdk.monitor.onNewConversation(() => { + console.log('New conversation detected'); +}); + +// Any USS state changed (preferences, settings, etc.) +sdk.monitor.onStateChanged((e) => { + console.log(`${e.key}: ${e.previousSize} → ${e.newSize} bytes`); +}); + +sdk.monitor.start(3000, 5000); // USS poll: 3s, trajectory poll: 5s +``` + +### Agent Step Control + +Programmatically accept, reject, or run agent actions — build approval workflows, auto-accept policies, or custom review UIs. + +```typescript +await sdk.cascade.acceptStep(); // Accept code edit +await sdk.cascade.rejectStep(); // Reject code edit +await sdk.cascade.acceptTerminalCommand(); // Accept terminal command +await sdk.cascade.rejectTerminalCommand(); // Reject terminal command +await sdk.cascade.runTerminalCommand(); // Run pending command +await sdk.cascade.acceptCommand(); // Accept non-terminal action +``` + +### State & Preferences + +Read the agent's current settings — terminal policies, secure mode, sandbox config, and more. Decoded directly from protobuf sentinel values. + +```typescript +const prefs = await sdk.cascade.getPreferences(); + +prefs.terminalExecutionPolicy // OFF | AUTO | EAGER +prefs.artifactReviewPolicy // ALWAYS | TURBO | AUTO +prefs.secureModeEnabled // boolean +prefs.terminalSandboxEnabled // boolean +prefs.shellIntegrationEnabled // boolean +prefs.allowNonWorkspaceFiles // boolean +// ... 16 preferences total +``` + +### IDE Diagnostics + +Access system information, extension logs, and recent conversation metadata. + +```typescript +const diag = await sdk.cascade.getDiagnostics(); + +console.log(diag.systemInfo.operatingSystem); +console.log(diag.systemInfo.userName); +console.log(diag.isRemote); // SSH? + +// MCP URL, browser port, git status +const mcpUrl = await sdk.cascade.getMcpUrl(); +const browserPort = await sdk.cascade.getBrowserPort(); +const ignored = await sdk.cascade.isFileGitIgnored('secret.env'); +``` + +### Headless Cascade (LSBridge) + +Create and manage conversations programmatically through the Language Server — no UI flicker, no panel switching. + +```typescript +import { Models } from 'antigravity-sdk'; + +// Create a headless cascade with model selection +const cascadeId = await sdk.ls.createCascade({ + text: 'Analyze test coverage in this project', + model: Models.GEMINI_FLASH, +}); + +// Send follow-up messages +await sdk.ls.sendMessage({ + cascadeId, + text: 'Now fix the failing tests', + model: Models.GEMINI_PRO_HIGH, +}); + +// Focus in UI when ready +await sdk.ls.focusCascade(cascadeId); + +// Or make raw RPC calls to any of the 68 verified LS methods +const status = await sdk.ls.getUserStatus(); +const cascades = await sdk.ls.listCascades(); +``` + +> [!NOTE] +> LSBridge auto-discovers the Language Server port and CSRF token from the running LS process. If auto-discovery fails (sandboxed environments), use `sdk.ls.setConnection(port, csrfToken)` manually. + +--- + +## Architecture + +``` +Your Extension + │ + ▼ +┌──────────────────────────────────────────┐ +│ antigravity-sdk │ +│ │ +│ sdk.cascade ← CascadeManager │ +│ Sessions, preferences, step control │ +│ │ +│ sdk.monitor ← EventMonitor │ +│ USS polling, trajectory tracking │ +│ │ +│ sdk.integration ← IntegrationManager │ +│ Declarative UI for Agent View │ +│ │ +│ sdk.commands ← CommandBridge │ +│ 60+ verified Antigravity commands │ +│ │ +│ sdk.state ← StateBridge │ +│ Read-only access to USS preferences │ +│ │ +│ sdk.ls ← LSBridge │ +│ Local LS communication (advanced) │ +│ │ +└────────────────────────────────────────-─┘ + │ + vscode.commands.executeCommand() + + read-only state.vscdb (sql.js) +``` + +> [!NOTE] +> The SDK uses `sql.js` (pure JS/WASM SQLite) instead of `better-sqlite3` because Antigravity's Electron ABI (v140 / Node v22.21.1) is incompatible with native modules. This was verified in runtime. + +--- + +## Compliance + +> [!CAUTION] +> **Token extraction is a violation of Google's Terms of Service.** +> +> The SDK **actively blocks** access to authentication tokens (`oauthToken`, `agentManagerInitState`, and other sensitive keys). Any attempt to read these keys will throw an error. +> +> Extracting, storing, forwarding, or reusing Antigravity OAuth tokens — directly or through third-party tools — violates Google's TOS and may result in account termination. + +### What this SDK is for + +- Building **VS Code extensions** that run inside Antigravity IDE +- Extending Antigravity's functionality for your own workflows +- Adding custom UI elements to the Agent View +- Monitoring and automating agent step approval +- Reading preferences and conversation metadata + +### What this SDK is NOT for + +- Integrating Antigravity with external applications or services +- Proxying or relaying requests to Google's infrastructure +- Extracting AI model outputs for training other models +- Accessing Google's backend servers, gRPC endpoints, or auth systems +- Building alternative clients or wrappers around Antigravity + +### How it works + +All SDK communication goes through three safe, local channels: + +1. **`vscode.commands.executeCommand()`** — the standard VS Code Extension API that all extensions use. Antigravity decides what to execute. +2. **Read-only local state** — the SDK reads `state.vscdb` for preferences and metadata, never writes. +3. **Local Language Server** — the SDK communicates with the LS process on `127.0.0.1` using the same ConnectRPC protocol that Antigravity itself uses. Authentication is via an ephemeral per-session CSRF token (not the user's OAuth token). No data leaves the local machine through this channel. + +The SDK includes a `SENSITIVE_KEYS` blocklist that prevents extension developers from accidentally (or intentionally) accessing authentication data. + +--- + +## Documentation + +- **[GEMINI.md](GEMINI.md)** — Full internal architecture docs, verified DOM selectors, protobuf schemas +- **[LEGAL.md](LEGAL.md)** — Legal notice, interoperability rights, compliance details +- **[API Reference](https://kanezal.github.io/antigravity-sdk)** — TypeDoc (coming soon) + +--- + +## Contributing + +This is a community project. PRs welcome! + +1. Fork the repo +2. Create a feature branch +3. Follow the existing code style +4. Add JSDoc comments for all public methods +5. Submit a PR + +--- + +## Disclaimer + +> [!WARNING] +> This project is not affiliated with Google or the Antigravity team. The SDK interacts with Antigravity through its existing extension API and local state files. Use at your own risk and in compliance with applicable terms of service. + +--- + +## License + +[AGPL-3.0-or-later](LICENSE) diff --git a/extension/src/sdk/index.d.ts b/extension/src/sdk/index.d.ts new file mode 100644 index 0000000..1753793 --- /dev/null +++ b/extension/src/sdk/index.d.ts @@ -0,0 +1,2297 @@ +import * as vscode from 'vscode'; + +/** + * Core type definitions for Antigravity SDK. + * + * These types mirror the internal protobuf schemas used by Antigravity's + * Language Server, extracted via reverse engineering of the minified source. + * + * @module types + */ +/** + * Terminal command auto-execution policy. + * + * Controls how terminal commands are handled when the agent requests execution. + */ +declare enum TerminalExecutionPolicy { + /** Always ask user before running */ + OFF = 1, + /** Auto-run safe commands, ask for potentially dangerous ones */ + AUTO = 2, + /** Always auto-run without asking */ + EAGER = 3 +} +/** + * Artifact review policy for code changes. + */ +declare enum ArtifactReviewPolicy { + /** Always show diff review */ + ALWAYS = 1, + /** Skip review for simple changes */ + TURBO = 2, + /** Automatically decide based on change complexity */ + AUTO = 3 +} +/** + * Type of a Cortex step (tool call) in a trajectory. + */ +declare enum CortexStepType { + RunCommand = "RunCommand", + WriteToFile = "WriteToFile", + ViewFile = "ViewFile", + ViewFileOutline = "ViewFileOutline", + ViewCodeItem = "ViewCodeItem", + SearchWeb = "SearchWeb", + ReadUrlContent = "ReadUrlContent", + OpenBrowserUrl = "OpenBrowserUrl", + ReadBrowserPage = "ReadBrowserPage", + ListBrowserPages = "ListBrowserPages", + ListDirectory = "ListDirectory", + FindByName = "FindByName", + CodebaseSearch = "CodebaseSearch", + GrepSearch = "GrepSearch", + SendCommandInput = "SendCommandInput", + ReadTerminal = "ReadTerminal", + ShellExec = "ShellExec", + McpTool = "McpTool", + InvokeSubagent = "InvokeSubagent", + Memory = "Memory", + KnowledgeGeneration = "KnowledgeGeneration", + UserInput = "UserInput", + SystemMessage = "SystemMessage", + PlannerResponse = "PlannerResponse", + Wait = "Wait", + ProposeCode = "ProposeCode", + WriteCascadeEdit = "WriteCascadeEdit" +} +/** + * Status of a Cortex step. + */ +declare enum StepStatus { + /** Step is being processed */ + Running = "running", + /** Step completed successfully */ + Completed = "completed", + /** Step failed */ + Failed = "failed", + /** Step is waiting for user interaction */ + WaitingForUser = "waiting_for_user", + /** Step was cancelled */ + Cancelled = "cancelled" +} +/** + * Type of trajectory (conversation). + */ +declare enum TrajectoryType { + /** Standard chat conversation */ + Chat = "chat", + /** Agent mode (Cascade) */ + Cascade = "cascade" +} +/** + * A single step (tool call) in a Cascade trajectory. + */ +interface ICortexStep { + /** Unique step identifier */ + readonly id: string; + /** Step index within the trajectory */ + readonly index: number; + /** Type of tool call */ + readonly type: CortexStepType; + /** Current status */ + readonly status: StepStatus; + /** Human-readable summary of what this step does */ + readonly summary: string; + /** Step-specific data (command line, file path, etc.) */ + readonly data: Record; + /** Internal metadata not shown in UI */ + readonly metadata: IStepMetadata; + /** Timestamp when step was created */ + readonly createdAt: Date; + /** Timestamp when step completed (if completed) */ + readonly completedAt?: Date; +} +/** + * Internal metadata attached to each step. + */ +interface IStepMetadata { + /** Raw protobuf fields from the server response */ + readonly rawFields: Record; + /** Token count for this step's input */ + readonly inputTokens?: number; + /** Token count for this step's output */ + readonly outputTokens?: number; + /** Model used for this step */ + readonly model?: string; + /** Whether this step was auto-approved */ + readonly autoApproved?: boolean; +} +/** + * A chat message in a conversation. + */ +interface IChatMessage { + /** Message role */ + readonly role: 'user' | 'assistant' | 'system'; + /** Message content */ + readonly content: string; + /** Message ID */ + readonly id: string; + /** Timestamp */ + readonly createdAt: Date; + /** Hidden metadata */ + readonly metadata: Record; +} +/** + * Information about the current context window usage. + */ +interface IContextInfo { + /** Total tokens currently in context */ + readonly totalTokens: number; + /** Maximum context window size */ + readonly maxTokens: number; + /** Usage as percentage (0-100) */ + readonly usagePercent: number; + /** Token breakdown by category */ + readonly breakdown: ITokenBreakdown; +} +/** + * Token usage breakdown. + */ +interface ITokenBreakdown { + /** System prompt tokens */ + readonly system: number; + /** User message tokens */ + readonly userMessages: number; + /** Assistant response tokens */ + readonly assistantMessages: number; + /** Tool call input tokens */ + readonly toolCalls: number; + /** Tool result tokens */ + readonly toolResults: number; +} +/** + * A Cascade session (conversation/trajectory). + */ +interface ISessionInfo { + /** Unique session/cascade ID */ + readonly id: string; + /** Session title (auto-generated or user-set) */ + readonly title: string; + /** When the session was created */ + readonly createdAt: Date; + /** When the session was last active */ + readonly lastActiveAt: Date; + /** Type of trajectory */ + readonly type: TrajectoryType; + /** Whether the session is currently active */ + readonly isActive: boolean; + /** Tags applied to this session */ + readonly tags: string[]; +} +/** + * Agent preferences from USS (Unified State Sync). + * + * All 16 sentinel keys verified from live state.vscdb on 2026-02-28. + */ +interface IAgentPreferences { + /** Terminal command auto-execution policy (terminalAutoExecutionPolicySentinelKey) */ + readonly terminalExecutionPolicy: TerminalExecutionPolicy; + /** Code change review policy (artifactReviewPolicySentinelKey) */ + readonly artifactReviewPolicy: ArtifactReviewPolicy; + /** Planning mode (planningModeSentinelKey) */ + readonly planningMode: number; + /** Whether strict/secure mode is enabled (secureModeSentinelKey) */ + readonly secureModeEnabled: boolean; + /** Whether terminal sandbox is enabled (enableTerminalSandboxSentinelKey) */ + readonly terminalSandboxEnabled: boolean; + /** Whether sandbox allows network access (sandboxAllowNetworkSentinelKey) */ + readonly sandboxAllowNetwork: boolean; + /** Whether shell integration is enabled (enableShellIntegrationSentinelKey) */ + readonly shellIntegrationEnabled: boolean; + /** Allow agent to access files outside workspace (allowAgentAccessNonWorkspaceFilesSentinelKey) */ + readonly allowNonWorkspaceFiles: boolean; + /** Allow Cascade to read .gitignore files (allowCascadeAccessGitignoreFilesSentinelKey) */ + readonly allowGitignoreAccess: boolean; + /** Explain and fix in current conversation (explainAndFixInCurrentConversationSentinelKey) */ + readonly explainFixInCurrentConvo: boolean; + /** Auto-continue on max generator invocations (autoContinueOnMaxGeneratorInvocationsSentinelKey) */ + readonly autoContinueOnMax: number; + /** Disable auto-open of edited files (disableAutoOpenEditedFilesSentinelKey) */ + readonly disableAutoOpenEdited: boolean; + /** Enable sounds for special events (enableSoundsForSpecialEventsSentinelKey) */ + readonly enableSounds: boolean; + /** Disable Cascade auto-fix for lint errors (disableCascadeAutoFixLintsSentinelKey) */ + readonly disableAutoFixLints: boolean; + /** Explicitly allowed terminal commands (terminalAllowedCommandsSentinelKey) */ + readonly allowedCommands: string[]; + /** Explicitly denied terminal commands (terminalDeniedCommandsSentinelKey) */ + readonly deniedCommands: string[]; +} +/** + * Model configuration. + */ +interface IModelConfig { + /** Model identifier */ + readonly id: string; + /** Human-readable model name */ + readonly name: string; + /** Whether this model is currently selected */ + readonly isActive: boolean; + /** Maximum context window size in tokens */ + readonly maxContextTokens: number; +} +/** + * Options for creating a new Cascade session. + */ +interface ICreateSessionOptions { + /** Initial task/message to send */ + readonly task: string; + /** Whether to run in background (don't focus the panel) */ + readonly background?: boolean; + /** Model to use (defaults to current) */ + readonly model?: string; +} +/** + * Agent state from the Agent Manager. + */ +interface IAgentState { + /** Whether the agent manager is enabled */ + readonly isEnabled: boolean; + /** Whether the agent is currently processing */ + readonly isProcessing: boolean; + /** Active cascade/conversation ID */ + readonly activeCascadeId: string | null; + /** Current model in use */ + readonly currentModel: string; +} +/** + * Trajectory entry from getDiagnostics.recentTrajectories. + * + * VERIFIED 2026-02-28: getDiagnostics returns clean JSON array with: + * { googleAgentId, trajectoryId, summary, lastStepIndex, lastModifiedTime } + */ +interface ITrajectoryEntry { + /** Conversation UUID = googleAgentId */ + readonly id: string; + /** Human-readable title = summary field */ + readonly title: string; + /** Current step index in this conversation */ + readonly stepCount: number; + /** Workspace URI (from USS protobuf fallback) */ + readonly workspaceUri: string; + /** Internal trajectory UUID (from getDiagnostics) */ + readonly trajectoryId?: string; + /** ISO timestamp of last modification (from getDiagnostics) */ + readonly lastModifiedTime?: string; +} +/** + * Diagnostics info from `antigravity.getDiagnostics`. + * + * VERIFIED: returns 176KB JSON string with 8 top-level keys: + * isRemote, systemInfo, extensionLogs, rendererLogs, + * mainThreadLogs, agentWindowConsoleLogs, languageServerLogs, + * recentTrajectories. + */ +interface IDiagnosticsInfo { + /** Whether IDE is running remotely (SSH) */ + readonly isRemote: boolean; + /** System info */ + readonly systemInfo: { + readonly operatingSystem: string; + readonly timestamp: string; + readonly userEmail: string; + readonly userName: string; + }; + /** Raw JSON for fields not yet typed */ + readonly raw: Record; +} + +/** + * Disposable pattern for resource cleanup. + * + * @module disposable + */ +/** + * An object that can release resources when no longer needed. + */ +interface IDisposable { + dispose(): void; +} +/** + * Collects multiple disposables and disposes them all at once. + * + * @example + * ```typescript + * const store = new DisposableStore(); + * store.add(someEventSub); + * store.add(anotherSub); + * // Later: + * store.dispose(); // cleans up everything + * ``` + */ +declare class DisposableStore implements IDisposable { + private readonly _disposables; + private _disposed; + /** + * Add a disposable to the store. + * + * @param disposable - The disposable to track + * @returns The same disposable (for chaining) + */ + add(disposable: T): T; + /** + * Dispose all tracked disposables. + */ + dispose(): void; +} +/** + * Creates a disposable from a cleanup function. + * + * @param fn - Cleanup function to call on dispose + */ +declare function toDisposable(fn: () => void): IDisposable; + +/** + * Lightweight event system for SDK. + * + * Follows VS Code's `Event` / `EventEmitter` pattern. + * Supports subscription, disposal, and one-shot listeners. + * + * @module events + */ + +/** + * A function that represents a subscription to an event. + * Call the returned disposable to unsubscribe. + */ +type Event = (listener: (e: T) => void) => IDisposable; +/** + * Emits events to registered listeners. + * + * @example + * ```typescript + * const emitter = new EventEmitter(); + * + * const sub = emitter.event((msg) => console.log(msg)); + * emitter.fire('hello'); // logs: hello + * sub.dispose(); + * emitter.fire('world'); // nothing happens + * ``` + */ +declare class EventEmitter implements IDisposable { + private _listeners; + private _disposed; + /** + * The event that listeners can subscribe to. + */ + readonly event: Event; + /** + * Fire the event, notifying all listeners. + * + * @param data - The event data to send to listeners + */ + fire(data: T): void; + /** + * Subscribe to the event, but only fire once. + * + * @param listener - Callback to invoke once + * @returns Disposable to cancel before the event fires + */ + once(listener: (e: T) => void): IDisposable; + /** + * Get the current number of listeners. + */ + get listenerCount(): number; + /** + * Dispose of the emitter and all listeners. + */ + dispose(): void; +} + +/** + * SDK-specific error classes. + * + * @module errors + */ +/** + * Base error for all Antigravity SDK errors. + */ +declare class AntigravitySDKError extends Error { + constructor(message: string); +} +/** + * Thrown when Antigravity IDE is not detected or not running. + */ +declare class AntigravityNotFoundError extends AntigravitySDKError { + constructor(); +} +/** + * Thrown when a command fails to execute. + */ +declare class CommandExecutionError extends AntigravitySDKError { + readonly command: string; + readonly reason: string; + constructor(command: string, reason: string); +} +/** + * Thrown when the state database cannot be read. + */ +declare class StateReadError extends AntigravitySDKError { + readonly key: string; + readonly reason: string; + constructor(key: string, reason: string); +} +/** + * Thrown when a session/conversation is not found. + */ +declare class SessionNotFoundError extends AntigravitySDKError { + readonly sessionId: string; + constructor(sessionId: string); +} + +/** + * Debug logger for SDK internals. + * + * Respects the `antigravitySDK.debug` setting. + * + * @module logger + */ +/** + * Log levels for SDK logging. + */ +declare enum LogLevel { + Debug = 0, + Info = 1, + Warn = 2, + Error = 3, + Off = 4 +} +/** + * SDK logger with level-based filtering. + * + * @example + * ```typescript + * const log = new Logger('CascadeManager'); + * log.debug('Loading sessions...'); + * log.info('Found 5 sessions'); + * log.error('Failed to load', err); + * ``` + */ +declare class Logger { + private readonly module; + private static _globalLevel; + /** + * Set the global log level for all SDK loggers. + * + * @param level - Minimum level to output + */ + static setLevel(level: LogLevel): void; + /** + * Create a logger for a specific module. + * + * @param module - Module name (shown in log prefix) + */ + constructor(module: string); + /** Log a debug message. */ + debug(message: string, ...args: unknown[]): void; + /** Log an informational message. */ + info(message: string, ...args: unknown[]): void; + /** Log a warning. */ + warn(message: string, ...args: unknown[]): void; + /** Log an error. */ + error(message: string, ...args: unknown[]): void; + private _log; +} + +/** + * Command Bridge — executes Antigravity internal commands via VS Code API. + * + * All commands go through `vscode.commands.executeCommand()` which is the + * safe, official way to interact with Antigravity from extensions. + * + * VERIFIED: All commands listed below were confirmed to exist in + * Antigravity v1.107.0 workbench.desktop.main.js and extension.js + * on 2026-02-28. + * + * @module transport/command-bridge + */ + +/** + * All known Antigravity commands, organized by category. + * + * Sources: workbench.desktop.main.js (160+ commands) + extension.js (45 commands) + */ +declare const AntigravityCommands: { + /** Open the Cascade agent panel */ + readonly OPEN_AGENT_PANEL: "antigravity.agentPanel.open"; + /** Focus the Cascade agent panel */ + readonly FOCUS_AGENT_PANEL: "antigravity.agentPanel.focus"; + /** Open the agent side panel */ + readonly OPEN_AGENT_SIDE_PANEL: "antigravity.agentSidePanel.open"; + /** Focus the agent side panel */ + readonly FOCUS_AGENT_SIDE_PANEL: "antigravity.agentSidePanel.focus"; + /** Toggle side panel visibility */ + readonly TOGGLE_SIDE_PANEL: "antigravity.agentSidePanel.toggleVisibility"; + /** Open agent (generic) */ + readonly OPEN_AGENT: "antigravity.openAgent"; + /** Toggle chat focus */ + readonly TOGGLE_CHAT_FOCUS: "antigravity.toggleChatFocus"; + /** Switch between workspace editor and agent view */ + readonly SWITCH_WORKSPACE_AGENT: "antigravity.switchBetweenWorkspaceAndAgent"; + /** Start a new conversation */ + readonly START_NEW_CONVERSATION: "antigravity.startNewConversation"; + /** Send a prompt to the agent panel */ + readonly SEND_PROMPT_TO_AGENT: "antigravity.sendPromptToAgentPanel"; + /** Send text to chat */ + readonly SEND_TEXT_TO_CHAT: "antigravity.sendTextToChat"; + /** Send a chat action message */ + readonly SEND_CHAT_ACTION: "antigravity.sendChatActionMessage"; + /** Set which conversation is visible */ + readonly SET_VISIBLE_CONVERSATION: "antigravity.setVisibleConversation"; + /** Execute a cascade action */ + readonly EXECUTE_CASCADE_ACTION: "antigravity.executeCascadeAction"; + /** Broadcast conversation deletion to all windows */ + readonly BROADCAST_CONVERSATION_DELETION: "antigravity.broadcastConversationDeletion"; + /** Track that a background conversation was created */ + readonly TRACK_BACKGROUND_CONVERSATION: "antigravity.trackBackgroundConversationCreated"; + /** Accept the current agent step */ + readonly ACCEPT_AGENT_STEP: "antigravity.agent.acceptAgentStep"; + /** Reject the current agent step */ + readonly REJECT_AGENT_STEP: "antigravity.agent.rejectAgentStep"; + /** Accept a pending command */ + readonly COMMAND_ACCEPT: "antigravity.command.accept"; + /** Reject a pending command */ + readonly COMMAND_REJECT: "antigravity.command.reject"; + /** Accept a terminal command */ + readonly TERMINAL_ACCEPT: "antigravity.terminalCommand.accept"; + /** Reject a terminal command */ + readonly TERMINAL_REJECT: "antigravity.terminalCommand.reject"; + /** Run a terminal command */ + readonly TERMINAL_RUN: "antigravity.terminalCommand.run"; + /** Open new conversation (prioritized) */ + readonly OPEN_NEW_CONVERSATION: "antigravity.prioritized.chat.openNewConversation"; + /** Notify terminal command started */ + readonly TERMINAL_COMMAND_START: "antigravity.onManagerTerminalCommandStart"; + /** Notify terminal command data */ + readonly TERMINAL_COMMAND_DATA: "antigravity.onManagerTerminalCommandData"; + /** Notify terminal command finished */ + readonly TERMINAL_COMMAND_FINISH: "antigravity.onManagerTerminalCommandFinish"; + /** Update last terminal command */ + readonly UPDATE_TERMINAL_LAST_COMMAND: "antigravity.updateTerminalLastCommand"; + /** Notify shell command completion */ + readonly ON_SHELL_COMPLETION: "antigravity.onShellCommandCompletion"; + /** Show managed terminal */ + readonly SHOW_MANAGED_TERMINAL: "antigravity.showManagedTerminal"; + /** Send terminal output to chat */ + readonly SEND_TERMINAL_TO_CHAT: "antigravity.sendTerminalToChat"; + /** Send terminal output to side panel */ + readonly SEND_TERMINAL_TO_SIDE_PANEL: "antigravity.sendTerminalToSidePanel"; + /** Initialize the agent */ + readonly INITIALIZE_AGENT: "antigravity.initializeAgent"; + /** Open conversation workspace picker */ + readonly OPEN_CONVERSATION_PICKER: "antigravity.openConversationWorkspaceQuickPick"; + /** Open conversation picker (alternative) */ + readonly OPEN_CONV_PICKER_ALT: "antigravity.openConversationPicker"; + /** Set working directories */ + readonly SET_WORKING_DIRS: "antigravity.setWorkingDirectories"; + /** Open review changes view */ + readonly OPEN_REVIEW_CHANGES: "antigravity.openReviewChanges"; + /** Open diff view */ + readonly OPEN_DIFF_VIEW: "antigravity.openDiffView"; + /** Open diff zones */ + readonly OPEN_DIFF_ZONES: "antigravity.openDiffZones"; + /** Close all diff zones */ + readonly CLOSE_ALL_DIFF_ZONES: "antigravity.closeAllDiffZones"; + /** Create a new rule */ + readonly CREATE_RULE: "antigravity.createRule"; + /** Create a new workflow */ + readonly CREATE_WORKFLOW: "antigravity.createWorkflow"; + /** Create a global workflow */ + readonly CREATE_GLOBAL_WORKFLOW: "antigravity.createGlobalWorkflow"; + /** Open global rules */ + readonly OPEN_GLOBAL_RULES: "antigravity.openGlobalRules"; + /** Open workspace rules */ + readonly OPEN_WORKSPACE_RULES: "antigravity.openWorkspaceRules"; + /** Open configure plugins page */ + readonly OPEN_CONFIGURE_PLUGINS: "antigravity.openConfigurePluginsPage"; + /** Get Cascade plugin template */ + readonly GET_PLUGIN_TEMPLATE: "antigravity.getCascadePluginTemplate"; + /** Poll MCP server states */ + readonly POLL_MCP_SERVERS: "antigravity.pollMcpServerStates"; + /** Open MCP config file */ + readonly OPEN_MCP_CONFIG: "antigravity.openMcpConfigFile"; + /** Open MCP docs page */ + readonly OPEN_MCP_DOCS: "antigravity.openMcpDocsPage"; + /** Update plugin installation count */ + readonly UPDATE_PLUGIN_COUNT: "antigravity.updatePluginInstallationCount"; + /** Enable autocomplete */ + readonly ENABLE_AUTOCOMPLETE: "antigravity.enableAutocomplete"; + /** Disable autocomplete */ + readonly DISABLE_AUTOCOMPLETE: "antigravity.disableAutocomplete"; + /** Accept completion */ + readonly ACCEPT_COMPLETION: "antigravity.acceptCompletion"; + /** Force supercomplete */ + readonly FORCE_SUPERCOMPLETE: "antigravity.forceSupercomplete"; + /** Snooze autocomplete temporarily */ + readonly SNOOZE_AUTOCOMPLETE: "antigravity.snoozeAutocomplete"; + /** Cancel snooze */ + readonly CANCEL_SNOOZE: "antigravity.cancelSnoozeAutocomplete"; + /** Login to Antigravity */ + readonly LOGIN: "antigravity.login"; + /** Cancel login */ + readonly CANCEL_LOGIN: "antigravity.cancelLogin"; + /** Handle auth refresh */ + readonly HANDLE_AUTH_REFRESH: "antigravity.handleAuthRefresh"; + /** Sign in to Antigravity */ + readonly SIGN_IN: "antigravity.SignInToAntigravity"; + /** Get diagnostics info */ + readonly GET_DIAGNOSTICS: "antigravity.getDiagnostics"; + /** Download diagnostics bundle */ + readonly DOWNLOAD_DIAGNOSTICS: "antigravity.downloadDiagnostics"; + /** Capture traces */ + readonly CAPTURE_TRACES: "antigravity.captureTraces"; + /** Enable tracing */ + readonly ENABLE_TRACING: "antigravity.enableTracing"; + /** Clear and disable tracing */ + readonly CLEAR_TRACING: "antigravity.clearAndDisableTracing"; + /** Get manager trace */ + readonly GET_MANAGER_TRACE: "antigravity.getManagerTrace"; + /** Get workbench trace */ + readonly GET_WORKBENCH_TRACE: "antigravity.getWorkbenchTrace"; + /** Toggle debug info widget */ + readonly TOGGLE_DEBUG_INFO: "antigravity.toggleDebugInfoWidget"; + /** Open troubleshooting */ + readonly OPEN_TROUBLESHOOTING: "antigravity.openTroubleshooting"; + /** Open issue reporter */ + readonly OPEN_ISSUE_REPORTER: "antigravity.openIssueReporter"; + /** Restart the language server */ + readonly RESTART_LANGUAGE_SERVER: "antigravity.restartLanguageServer"; + /** Kill language server and reload window */ + readonly KILL_LS_AND_RELOAD: "antigravity.killLanguageServerAndReloadWindow"; + /** Generate commit message via AI */ + readonly GENERATE_COMMIT_MESSAGE: "antigravity.generateCommitMessage"; + /** Cancel commit message generation */ + readonly CANCEL_COMMIT_MESSAGE: "antigravity.cancelGenerateCommitMessage"; + /** Open browser */ + readonly OPEN_BROWSER: "antigravity.openBrowser"; + /** Get browser onboarding port (returns number, e.g. 57401) */ + readonly GET_BROWSER_PORT: "antigravity.getBrowserOnboardingPort"; + /** Open quick settings panel */ + readonly OPEN_QUICK_SETTINGS: "antigravity.openQuickSettingsPanel"; + /** Open customizations tab */ + readonly OPEN_CUSTOMIZATIONS: "antigravity.openCustomizationsTab"; + /** Import VS Code settings */ + readonly IMPORT_VSCODE_SETTINGS: "antigravity.importVSCodeSettings"; + /** Import VS Code extensions */ + readonly IMPORT_VSCODE_EXTENSIONS: "antigravity.importVSCodeExtensions"; + /** Import Cursor settings */ + readonly IMPORT_CURSOR_SETTINGS: "antigravity.importCursorSettings"; + /** Import Cursor extensions */ + readonly IMPORT_CURSOR_EXTENSIONS: "antigravity.importCursorExtensions"; + /** Reload window */ + readonly RELOAD_WINDOW: "antigravity.reloadWindow"; + /** Open documentation */ + readonly OPEN_DOCS: "antigravity.openDocs"; + /** Open changelog */ + readonly OPEN_CHANGELOG: "antigravity.openChangeLog"; + /** Explain and fix problem (from diagnostics) */ + readonly EXPLAIN_AND_FIX: "antigravity.explainAndFixProblem"; + /** Open a URL */ + readonly OPEN_URL: "antigravity.openGenericUrl"; + /** Editor mode settings */ + readonly EDITOR_MODE_SETTINGS: "antigravity.editorModeSettings"; +}; +/** + * Bridges between the SDK and Antigravity's command system. + * + * All interactions with Antigravity go through registered VS Code commands, + * ensuring we never bypass the official extension API. + * + * @example + * ```typescript + * const bridge = new CommandBridge(); + * + * // Open the agent panel + * await bridge.execute(AntigravityCommands.OPEN_AGENT_PANEL); + * + * // Start a new conversation + * await bridge.execute(AntigravityCommands.START_NEW_CONVERSATION); + * + * // Send a prompt + * await bridge.execute(AntigravityCommands.SEND_PROMPT_TO_AGENT, 'Hello!'); + * ``` + */ +declare class CommandBridge implements IDisposable { + private _disposed; + /** + * Execute an Antigravity command. + * + * @param command - The command ID to execute + * @param args - Arguments to pass to the command + * @returns The command's return value + * @throws {CommandExecutionError} If the command fails + */ + execute(command: string, ...args: unknown[]): Promise; + /** + * Check if a command is registered and available. + * + * @param command - Command ID to check + * @returns true if the command exists + */ + isAvailable(command: string): Promise; + /** + * Get all registered Antigravity commands. + * + * @returns List of command IDs starting with 'antigravity.' + */ + getAntigravityCommands(): Promise; + /** + * Register a command handler. + * + * @param command - Command ID to register + * @param handler - Function to handle the command + * @returns Disposable to unregister the command + */ + register(command: string, handler: (...args: unknown[]) => unknown): IDisposable; + dispose(): void; +} + +/** + * State Bridge — reads Antigravity's USS state from the SQLite database. + * + * Antigravity stores settings, conversation metadata, and agent preferences + * in `state.vscdb` (SQLite). This bridge provides read-only access to that data. + * + * VERIFIED against live state.vscdb on 2026-02-28. + * + * @module transport/state-bridge + */ + +/** + * USS (Unified State Sync) keys in state.vscdb. + * + * VERIFIED: All keys listed below were confirmed to exist + * in a live Antigravity v1.107.0 installation on 2026-02-28. + * Values are Base64-encoded protobuf unless noted otherwise. + */ +declare const USSKeys: { + /** Agent preferences — terminal policy, review policy, secure mode, etc. (1020 bytes) */ + readonly AGENT_PREFERENCES: "antigravityUnifiedStateSync.agentPreferences"; + /** Conversation/trajectory summaries — titles, timestamps, workspace URIs (74KB+) */ + readonly TRAJECTORY_SUMMARIES: "antigravityUnifiedStateSync.trajectorySummaries"; + /** Agent manager window state (192 bytes) */ + readonly AGENT_MANAGER_WINDOW: "antigravityUnifiedStateSync.agentManagerWindow"; + /** Enterprise override store (56 bytes) */ + readonly OVERRIDE_STORE: "antigravityUnifiedStateSync.overrideStore"; + /** Model preferences — selected model, sentinel key */ + readonly MODEL_PREFERENCES: "antigravityUnifiedStateSync.modelPreferences"; + /** Artifact review state (1204 bytes) */ + readonly ARTIFACT_REVIEW: "antigravityUnifiedStateSync.artifactReview"; + /** Browser preferences (380 bytes) */ + readonly BROWSER_PREFERENCES: "antigravityUnifiedStateSync.browserPreferences"; + /** Editor preferences (108 bytes) */ + readonly EDITOR_PREFERENCES: "antigravityUnifiedStateSync.editorPreferences"; + /** Tab preferences (404 bytes) */ + readonly TAB_PREFERENCES: "antigravityUnifiedStateSync.tabPreferences"; + /** Window preferences (44 bytes) */ + readonly WINDOW_PREFERENCES: "antigravityUnifiedStateSync.windowPreferences"; + /** Scratch/playground workspaces (268 bytes) */ + readonly SCRATCH_WORKSPACES: "antigravityUnifiedStateSync.scratchWorkspaces"; + /** Sidebar workspaces — recent workspace list (5604 bytes) */ + readonly SIDEBAR_WORKSPACES: "antigravityUnifiedStateSync.sidebarWorkspaces"; + /** User status info (5196 bytes) */ + readonly USER_STATUS: "antigravityUnifiedStateSync.userStatus"; + /** Model credits/usage info */ + readonly MODEL_CREDITS: "antigravityUnifiedStateSync.modelCredits"; + /** Onboarding state (140 bytes) */ + readonly ONBOARDING: "antigravityUnifiedStateSync.onboarding"; + /** Seen NUX (new user experience) IDs (76 bytes) */ + readonly SEEN_NUX_IDS: "antigravityUnifiedStateSync.seenNuxIds"; + /** Agent manager initialization state — contains auth tokens, workspace map (5144 bytes) */ + readonly AGENT_MANAGER_INIT: "jetskiStateSync.agentManagerInitState"; + /** All user settings — JSON format */ + readonly ALL_USER_SETTINGS: "antigravityUserSettings.allUserSettings"; + /** Allowed model configs for commands */ + readonly ALLOWED_COMMAND_MODEL_CONFIGS: "antigravity_allowed_command_model_configs"; + /** Chat session store index (JSON: {"version":1,"entries":{}}) */ + readonly CHAT_SESSION_INDEX: "chat.ChatSessionStore.index"; +}; +/** + * Reads Antigravity's internal state from the SQLite database. + * + * Uses **sql.js** (pure JavaScript SQLite, compiled to WASM) which is + * verified to work in Antigravity's Extension Host (unlike better-sqlite3 + * which fails due to ABI mismatch with Electron v22.21.1 / ABI v140). + * + * @example + * ```typescript + * const bridge = new StateBridge(); + * await bridge.initialize(); + * + * const prefs = await bridge.getAgentPreferences(); + * console.log(prefs.terminalExecutionPolicy); + * ``` + */ +declare class StateBridge implements IDisposable { + private _dbPath; + private _db; + private _disposed; + /** + * Initialize the state bridge by locating and opening state database. + * + * @throws {StateReadError} If the database cannot be found + */ + initialize(): Promise; + /** + * Read a raw value from the state database. + * + * @param key - The SQLite key to read + * @returns The raw string value, or null if not found + * @throws {StateReadError} If the key is sensitive or read fails + */ + getRawValue(key: string): Promise; + /** + * Get agent preferences from USS. + * + * @returns Parsed agent preferences + */ + getAgentPreferences(): Promise; + /** + * Get all stored USS keys from the state database. + * + * @returns List of key names related to Antigravity (excludes sensitive keys) + */ + getAntigravityKeys(): Promise; + /** + * Query using sql.js (in-process, pure JS). + */ + private _querySqlJs; + /** + * Query using child_process sqlite3 CLI (fallback). + */ + private _queryChildProcess; + /** + * Locate the state.vscdb file across platforms. + */ + private _findStateDb; + /** + * Parse agent preferences from Base64(Protobuf). + * + * The protobuf structure uses "sentinel keys" as string fields: + * - `planningModeSentinelKey` → nested message with Base64(varint) + * - `terminalAutoExecutionPolicySentinelKey` → nested message with Base64(varint) + * - `artifactReviewPolicySentinelKey` → nested message with Base64(varint) + * + * Each sentinel value is itself a small Base64 string (e.g., "EAM=" = varint 3 = EAGER). + */ + private _parseAgentPreferences; + /** + * Extract a varint value from a protobuf sentinel key. + * + * The structure is: sentinel_key_string followed by a small + * Base64 value like "EAM=" (which decodes to a protobuf varint). + * + * Known mappings: + * - "CAE=" → field 1, value 1 (OFF / ALWAYS) + * - "EAI=" → field 2, value 2 (AUTO / TURBO) + * - "EAM=" → field 2, value 3 (EAGER / AUTO) + */ + private _extractSentinelValue; + private _defaultPreferences; + dispose(): void; +} + +/** + * Event Monitor — polls state.vscdb and getDiagnostics for changes. + * + * Detects: + * - USS key changes (trajectory summaries, preferences, etc.) + * - Step count changes per session (via getDiagnostics.recentTrajectories) + * - Active session switches + * - New conversations + * + * @module transport/event-monitor + */ + +/** + * USS key change event. + */ +interface IStateChange { + /** Which USS key changed */ + readonly key: string; + /** New data size */ + readonly newSize: number; + /** Previous data size */ + readonly previousSize: number; +} +/** + * Step count change event — fired when the agent adds/processes steps. + */ +interface IStepCountChange { + /** Conversation UUID (googleAgentId) */ + readonly sessionId: string; + /** Conversation title */ + readonly title: string; + /** Previous step count */ + readonly previousCount: number; + /** New step count */ + readonly newCount: number; + /** Number of new steps added */ + readonly delta: number; +} +/** + * Active session change event. + */ +interface IActiveSessionChange { + /** New active session ID */ + readonly sessionId: string; + /** New active session title */ + readonly title: string; + /** Previous active session ID (empty if first detection) */ + readonly previousSessionId: string; +} +/** + * Monitors Antigravity state for changes. + * + * Two polling modes: + * 1. **USS polling** — watches state.vscdb keys for size changes (lightweight) + * 2. **Trajectory polling** — watches getDiagnostics for step count changes (heavier, optional) + * + * @example + * ```typescript + * const monitor = new EventMonitor(stateBridge); + * + * // React to step changes (agent is working) + * monitor.onStepCountChanged((e) => { + * console.log(`${e.title}: +${e.delta} steps (now ${e.newCount})`); + * }); + * + * // React to conversation switches + * monitor.onActiveSessionChanged((e) => { + * console.log(`Switched to: ${e.title}`); + * }); + * + * monitor.start(3000); + * ``` + */ +declare class EventMonitor implements IDisposable { + private readonly _state; + private readonly _disposables; + private _ussTimer; + private _trajTimer; + private _ussSnapshots; + private _trajSnapshots; + private _activeSessionId; + private _running; + private readonly _onStateChanged; + /** Fires when any monitored USS key changes size */ + readonly onStateChanged: Event; + private readonly _onNewConversation; + /** Fires when trajectory summaries grow (new conversation likely) */ + readonly onNewConversation: Event; + private readonly _onStepCountChanged; + /** Fires when a session's step count changes (agent made progress) */ + readonly onStepCountChanged: Event; + private readonly _onActiveSessionChanged; + /** Fires when the active (most recent) session changes */ + readonly onActiveSessionChanged: Event; + /** Keys we monitor for USS changes */ + private readonly _watchedKeys; + constructor(_state: StateBridge); + /** + * Start polling for state changes. + * + * @param intervalMs - USS polling interval (default: 3000ms) + * @param trajectoryIntervalMs - Trajectory polling interval (default: 5000ms). + * Set to 0 to disable trajectory polling (saves CPU). + */ + start(intervalMs?: number, trajectoryIntervalMs?: number): void; + /** + * Stop polling. + */ + stop(): void; + /** Check if the monitor is currently running. */ + get isRunning(): boolean; + /** Get the currently active session ID. */ + get activeSessionId(): string; + private _takeUSSSnapshot; + private _pollUSS; + private _pollTrajectories; + dispose(): void; +} + +/** + * Language Server Bridge — Direct ConnectRPC calls to the local LS. + * + * UPDATED 2026-03-01 (v1.3.0): + * Fixed CSRF token authentication (Issue #1). + * The LS binary is launched with --csrf_token as a CLI argument. + * Previous versions did not send this token, causing 401 "missing CSRF token". + * + * Discovery strategy (multi-layer): + * 1. Process CLI args — extract --port and --csrf_token from LS process + * 2. getDiagnostics console logs — fallback for port discovery + * 3. Manual override — setConnection(port, csrfToken) + * + * Service: exa.language_server_pb.LanguageServerService + * Protocol: HTTPS POST with JSON body + x-csrf-token header + * + * @module transport/ls-bridge + */ +/** Known model IDs (verified 2026-02-28) */ +declare const Models: { + readonly GEMINI_FLASH: 1018; + readonly GEMINI_PRO_LOW: 1164; + readonly GEMINI_PRO_HIGH: 1165; + readonly CLAUDE_SONNET: 1163; + readonly CLAUDE_OPUS: 1154; + readonly GPT_OSS: 342; +}; +type ModelId = typeof Models[keyof typeof Models] | number; +/** Options for creating a headless cascade */ +interface IHeadlessCascadeOptions { + /** Text prompt to send */ + text: string; + /** Model ID (default: Gemini 3 Flash = 1018) */ + model?: ModelId; + /** Planner type: 'conversational' (default) or 'normal' */ + plannerType?: 'conversational' | 'normal'; +} +/** Options for sending a message to existing cascade */ +interface ISendMessageOptions { + /** Target cascade ID */ + cascadeId: string; + /** Text to send */ + text: string; + /** Model ID (default: Gemini 3 Flash = 1018) */ + model?: ModelId; +} +/** + * Conversation annotation fields (from jetski_cortex.proto ConversationAnnotations). + * + * These are metadata annotations on a conversation that the user can set. + * The LS stores these natively and they persist across sessions. + */ +interface IConversationAnnotations { + /** Custom user title -- overrides the auto-generated summary */ + title?: string; + /** Tags/labels for organization */ + tags?: string[]; + /** Whether this conversation is archived */ + archived?: boolean; + /** Whether this conversation is starred (pinned) */ + starred?: boolean; +} +/** + * Direct bridge to the Language Server via ConnectRPC. + * + * Discovers the LS port and CSRF token from the LS process CLI args, + * then makes authenticated HTTPS POST calls to the LS endpoints. + * + * @example + * ```typescript + * const ls = new LSBridge(commandBridge); + * await ls.initialize(); + * + * // Create a headless cascade + * const cascadeId = await ls.createCascade({ + * text: 'Analyze test coverage', + * model: Models.GEMINI_FLASH, + * }); + * + * // Send follow-up + * await ls.sendMessage({ cascadeId, text: 'Focus on edge cases' }); + * + * // Switch UI to it + * await ls.focusCascade(cascadeId); + * ``` + */ +declare class LSBridge { + private _port; + private _csrfToken; + private _useTls; + private _executeCommand; + constructor(executeCommand: (command: string, ...args: any[]) => Promise); + /** + * Discover the Language Server port and CSRF token. + * Must be called before other methods. + * + * Discovery chain: + * 1. Parse LS process CLI arguments (--port, --csrf_token) + * 2. Fallback: getDiagnostics console logs (port only) + * 3. Manual: call setConnection() after initialize() returns false + */ + initialize(): Promise; + /** Whether the bridge is ready (port discovered) */ + get isReady(): boolean; + /** The discovered LS port */ + get port(): number | null; + /** Whether CSRF token is available */ + get hasCsrfToken(): boolean; + /** + * Manually set the LS connection parameters. + * + * Use this when auto-discovery fails (e.g., non-standard install, + * or you've discovered the port/token through other means like `lsof`). + * + * @param port - LS port number + * @param csrfToken - CSRF token from LS process CLI args + * @param useTls - Whether to use HTTPS (default: false, extension_server uses HTTP) + * + * @example + * ```typescript + * const ls = new LSBridge(commandBridge); + * const ok = await ls.initialize(); + * if (!ok) { + * // Manual fallback: get port and csrf from your own discovery + * ls.setConnection(54321, 'abc123-csrf-token'); + * } + * ``` + */ + setConnection(port: number, csrfToken: string, useTls?: boolean): void; + /** + * Create a new cascade and optionally send a message. + * Fully headless — no UI panel opened, no conversation switched. + * + * @returns cascadeId or null on failure + */ + createCascade(options: IHeadlessCascadeOptions): Promise; + /** + * Send a message to an existing cascade. + * + * @returns true if sent successfully + */ + sendMessage(options: ISendMessageOptions): Promise; + /** + * Switch the UI to show a specific cascade conversation. + */ + focusCascade(cascadeId: string): Promise; + /** + * Cancel a running cascade invocation. + */ + cancelCascade(cascadeId: string): Promise; + /** + * Native conversation annotations (verified from jetski_cortex.proto). + * + * ConversationAnnotations protobuf fields: + * - title (string) — custom user title, overrides auto-summary + * - tags (string[]) — tags/labels + * - archived (bool) — archive status + * - starred (bool) — pinned/starred + * - last_user_view_time (Timestamp) + * + * @param cascadeId - Conversation ID + * @param annotations - Partial annotation fields to set + * @param merge - If true, merge with existing annotations (default: true) + */ + updateAnnotations(cascadeId: string, annotations: IConversationAnnotations, merge?: boolean): Promise; + /** + * Set a custom title for a conversation. + * + * This sets the `title` field in ConversationAnnotations. + * When set, this title should be displayed instead of the + * auto-generated `summary` from the LLM. + * + * @param cascadeId - Conversation ID + * @param title - Custom title to set + */ + setTitle(cascadeId: string, title: string): Promise; + /** + * Star (pin) or unstar a conversation. + * + * This sets the `starred` field in ConversationAnnotations. + * + * @param cascadeId - Conversation ID + * @param starred - true to star, false to unstar + */ + setStar(cascadeId: string, starred: boolean): Promise; + /** + * Get details of a specific conversation. + */ + getConversation(cascadeId: string): Promise; + /** + * Get all cascade trajectories (conversation list). + */ + listCascades(): Promise; + /** + * Get trajectory descriptions (lighter than full trajectories). + * Returns { trajectories: [...] }. + */ + getTrajectoryDescriptions(): Promise; + /** + * Get user status (tier, models, etc.) + */ + getUserStatus(): Promise; + /** + * Make a raw RPC call to any LS method. + * @param method - RPC method name (e.g. 'StartCascade') + * @param payload - JSON payload + */ + rawRPC(method: string, payload: any): Promise; + private _ensureReady; + private _sendMessage; + /** + * Discover LS port and CSRF token from the Language Server process. + * + * VERIFIED 2026-03-01 from Antigravity extension.js source: + * + * 1. CSRF header is "x-codeium-csrf-token" (NOT x-csrf-token) + * 2. CSRF value is --csrf_token from CLI (NOT --extension_server_csrf_token) + * 3. ConnectRPC endpoint is on httpsPort (HTTPS) or httpPort (HTTP) + * These ports are NOT in CLI args (--random_port flag means random). + * We discover them via netstat/PID, excluding extension_server_port. + * + * Source code proof: + * n.header.set("x-codeium-csrf-token", e) // header name + * address = `127.0.0.1:${te.httpsPort}` // ConnectRPC address + * csrfToken = a = d.randomUUID() → --csrf_token // token source + * t.headers["x-codeium-csrf-token"] === this.csrfToken ? ... : 403 + * + * Discovery: 2 phases + * Phase 1: Get-CimInstance/ps → PID, --csrf_token, --extension_server_port + * Phase 2: netstat → find LISTENING ports for PID, exclude ext_server_port + */ + private _discoverFromProcess; + /** + * Phase 1: Find the LS process for this workspace. + */ + private _findLSProcess; + /** + * Phase 2: Find ConnectRPC port via netstat. + * + * The LS process listens on multiple ports: + * - httpsPort (HTTPS, ConnectRPC) ← this is what we want + * - httpPort (HTTP, ConnectRPC) ← also works + * - lspPort (LSP JSON-RPC) + * - extension_server_port is separate (for Extension Host IPC) + * + * We find all LISTENING ports for the LS PID, exclude ext_server_port, + * then try HTTPS first (preferred), fall back to HTTP. + */ + private _findConnectPort; + /** + * Quick probe: check if a port accepts ConnectRPC requests. + * Returns true if the port responds (even with error) on the given protocol. + */ + private _probePort; + /** + * Get a workspace hint string used to match the correct LS process. + * + * The LS process has --workspace_id like: + * file_d_3A_programming_better_antigravity + * which is an encoded version of the workspace URI. + */ + private _getWorkspaceHint; + /** + * Extract a CLI argument value from a command-line string. + * Supports both --key=value and --key value formats. + */ + private _extractArg; + /** + * Fallback: discover port from getDiagnostics console logs. + * NOTE: This does NOT discover the CSRF token. + * In recent Antigravity versions, the port URL may no longer appear in logs. + */ + private _discoverPortFromDiagnostics; + /** + * Make an authenticated RPC call to the Language Server. + * Sends x-csrf-token header when available. + * + * VERIFIED 2026-03-01: + * - extension_server_port uses plain HTTP (no TLS) + * - Main LS port (--random_port) uses HTTPS with self-signed cert + */ + private _rpc; +} + +/** + * Cascade Manager — Session listing, creation, and monitoring. + * + * Provides high-level API to interact with Cascade conversations + * using verified transport layer (CommandBridge + StateBridge). + * + * VERIFIED 2026-02-28: getDiagnostics.recentTrajectories returns clean JSON + * with { googleAgentId, trajectoryId, summary, lastStepIndex, lastModifiedTime }. + * + * @module cascade/cascade-manager + */ + +/** + * Manages Cascade conversations. + * + * Primary data source: `antigravity.getDiagnostics` → `recentTrajectories` + * Fallback: `antigravityUnifiedStateSync.trajectorySummaries` protobuf parsing + * + * @example + * ```typescript + * const manager = new CascadeManager(commands, state); + * await manager.initialize(); + * + * // List sessions (real titles from getDiagnostics) + * const sessions = await manager.getSessions(); + * sessions.forEach(s => console.log(`${s.title} (step ${s.stepCount})`)); + * + * // Read preferences (all 16 sentinel values) + * const prefs = await manager.getPreferences(); + * + * // Create & send + * await manager.createSession({ task: 'Analyze coverage', background: true }); + * ``` + */ +declare class CascadeManager implements IDisposable { + private readonly _commands; + private readonly _state; + private readonly _disposables; + private _sessions; + private _initialized; + private readonly _onSessionsChanged; + /** Fires when the session list changes */ + readonly onSessionsChanged: Event; + constructor(_commands: CommandBridge, _state: StateBridge); + /** + * Initialize the cascade manager. + * Loads the initial session list from getDiagnostics. + */ + initialize(): Promise; + /** + * Get all known Cascade sessions. + * + * Uses `getDiagnostics.recentTrajectories` (clean JSON with titles). + * + * @returns List of trajectory entries sorted by recency + */ + getSessions(): Promise; + /** + * Refresh the session list. + * + * @returns Updated session list + */ + refreshSessions(): Promise; + /** + * Get agent preferences (all 16 sentinel values). + */ + getPreferences(): Promise; + /** + * Get IDE diagnostics (176KB JSON with system info, logs, trajectories). + * + * Structure (verified): + * - isRemote, systemInfo (OS, user, email) + * - extensionLogs (Array[375]) + * - rendererLogs, mainThreadLogs, agentWindowConsoleLogs + * - languageServerLogs + * - recentTrajectories (Array[10]) + * + * @returns Parsed diagnostics information + */ + getDiagnostics(): Promise; + /** + * Get the Chrome DevTools MCP URL. + * + * Verified: returns `http://127.0.0.1:{port}/mcp` + * + * @returns MCP URL string + */ + getMcpUrl(): Promise; + /** + * Check if a file is gitignored. + * + * @param filePath - Relative or absolute file path + * @returns true if gitignored, false/null otherwise + */ + isFileGitIgnored(filePath: string): Promise; + /** + * Create a new Cascade conversation via VS Code commands. + * + * ⚠️ **FALLBACK APPROACH** — causes UI flickering. + * For true headless creation, use `sdk.ls.createCascade()` + * from the SDK's LS bridge (see LSBridge module). + * + * VERIFIED 2026-02-28: + * - `startNewConversation` ✅ creates new chat (but switches UI) + * - `prioritized.chat.openNewConversation` ❌ does NOT create new + * - `sendPromptToAgentPanel` ✅ sends to currently visible chat (always opens panel) + * - `sendTextToChat` ❌ does not visibly work + * + * @param options - Session creation options + * @returns Session ID (googleAgentId) or empty string if not detected + */ + createSession(options: ICreateSessionOptions): Promise; + /** + * Create a background Cascade conversation via commands. + * + * ⚠️ **FALLBACK** — Uses quick-switch approach (UI flickers briefly). + * For true headless background sessions, use the SDK's LS bridge: + * ```typescript + * // Using LSBridge: + * const cascadeId = await sdk.ls.createCascade({ text: 'task', modelId: 1018 }); + * ``` + * + * @param task - Initial task/prompt to send + * @returns Session ID or empty string + */ + createBackgroundSession(task: string): Promise; + /** + * Send a message to the active Cascade conversation. + * + * Uses `antigravity.sendTextToChat` — the primary text sending command. + */ + sendMessage(text: string): Promise; + /** + * Send a prompt directly to the agent panel. + * + * Uses `antigravity.sendPromptToAgentPanel` — focuses the agent panel. + */ + sendPrompt(text: string): Promise; + /** + * Send a chat action message (e.g., typing indicator, feedback). + * + * Uses `antigravity.sendChatActionMessage`. + */ + sendChatAction(action: string): Promise; + /** + * Switch to a specific conversation. + * + * @param sessionId - Conversation UUID (googleAgentId) + */ + focusSession(sessionId: string): Promise; + /** + * Open a new conversation in the agent panel (prioritized command). + * + * Uses `antigravity.prioritized.chat.openNewConversation` which both + * opens the panel AND creates a fresh conversation. + */ + openNewConversation(): Promise; + /** + * Execute a Cascade action. + * + * Uses `antigravity.executeCascadeAction`. + * + * @param action - Action data to execute + */ + executeCascadeAction(action: unknown): Promise; + /** + * Accept the current agent step (code edit, file write, etc.). + * + * Uses `antigravity.agent.acceptAgentStep`. + */ + acceptStep(): Promise; + /** Reject the current agent step. */ + rejectStep(): Promise; + /** + * Accept a pending command (non-terminal, e.g. file edit confirmation). + * + * Uses `antigravity.command.accept`. + * This is DIFFERENT from terminalCommand.accept. + */ + acceptCommand(): Promise; + /** Reject a pending command (non-terminal). */ + rejectCommand(): Promise; + /** + * Accept a pending terminal command. + * + * Uses `antigravity.terminalCommand.accept`. + */ + acceptTerminalCommand(): Promise; + /** Reject a pending terminal command. */ + rejectTerminalCommand(): Promise; + /** Run a pending terminal command. */ + runTerminalCommand(): Promise; + /** Open the Cascade agent panel */ + openPanel(): Promise; + /** Focus the Cascade agent panel */ + focusPanel(): Promise; + /** Open the agent side panel */ + openSidePanel(): Promise; + /** Focus the agent side panel */ + focusSidePanel(): Promise; + /** + * Get the browser integration port (e.g., 57401). + */ + getBrowserPort(): Promise; + /** + * Load sessions from getDiagnostics.recentTrajectories (clean JSON). + * + * VERIFIED structure per entry: + * { + * googleAgentId: "uuid", ← conversation ID + * trajectoryId: "uuid", ← internal trajectory ID + * summary: "title", ← human-readable title + * lastStepIndex: 992, ← step count + * lastModifiedTime: "ISO" ← last activity + * } + */ + private _loadSessions; + /** + * Fallback: extract sessions from USS trajectory summaries protobuf. + */ + private _loadSessionsFromUSS; + /** + * Wait for a new session to appear in getDiagnostics. + * Polls every 500ms up to timeoutMs. + * + * @returns New session ID or empty string if timeout + */ + private _waitForNewSession; + /** + * Simple delay utility. + */ + private _delay; + dispose(): void; +} + +/** + * Integration module types — standardized UI integration points + * for the Antigravity Agent View. + * + * @module integration/types + */ +/** + * Standardized integration points in the Agent View UI. + * + * Each point corresponds to a specific DOM location in the + * Antigravity chat interface (verified 2026-02-28). + */ +declare enum IntegrationPoint { + /** Top bar — next to +, refresh, ... icons */ + TOP_BAR = "topBar", + /** Top right corner — before the X (close) button */ + TOP_RIGHT = "topRight", + /** Input area — next to voice/send buttons */ + INPUT_AREA = "inputArea", + /** Bottom icon row — file, terminal, artifact, chrome icons */ + BOTTOM_ICONS = "bottomIcons", + /** Per-turn metadata — appended inside each conversation turn */ + TURN_METADATA = "turnMeta", + /** User message badge — small badge inside user message bubbles */ + USER_BADGE = "userBadge", + /** Bot response action — button next to Good/Bad feedback */ + BOT_ACTION = "botAction", + /** 3-dot dropdown menu — extra items in the overflow menu */ + DROPDOWN_MENU = "dropdownMenu", + /** Chat title bar — interaction on conversation title */ + CHAT_TITLE = "chatTitle" +} +/** + * Base configuration for all integration points. + */ +interface IIntegrationBase { + /** Unique ID for this integration (prevents duplicates) */ + id: string; + /** Which integration point to target */ + point: IntegrationPoint; + /** Whether this integration is enabled (default: true) */ + enabled?: boolean; +} +/** + * Configuration for button-type integrations (top bar, input area, etc.). + */ +interface IButtonIntegration extends IIntegrationBase { + point: IntegrationPoint.TOP_BAR | IntegrationPoint.TOP_RIGHT | IntegrationPoint.INPUT_AREA | IntegrationPoint.BOTTOM_ICONS; + /** Icon (emoji or text glyph) */ + icon: string; + /** Tooltip text */ + tooltip?: string; + /** Toast to show on click */ + toast?: IToastConfig; + /** CSS class override */ + className?: string; +} +/** + * Configuration for turn-level metadata integration. + */ +interface ITurnMetaIntegration extends IIntegrationBase { + point: IntegrationPoint.TURN_METADATA; + /** Which metrics to display */ + metrics: TurnMetric[]; + /** Whether turns are clickable to show details toast */ + clickable?: boolean; +} +/** + * Configuration for user message badges. + */ +interface IUserBadgeIntegration extends IIntegrationBase { + point: IntegrationPoint.USER_BADGE; + /** What to show in the badge */ + display: 'charCount' | 'wordCount' | 'custom'; + /** Custom formatter function body (receives `textLength` as arg) */ + customFormat?: string; +} +/** + * Configuration for bot response action buttons. + */ +interface IBotActionIntegration extends IIntegrationBase { + point: IntegrationPoint.BOT_ACTION; + /** Icon */ + icon: string; + /** Label text */ + label: string; + /** Toast config on click */ + toast?: IToastConfig; +} +/** + * Configuration for dropdown menu items. + */ +interface IDropdownIntegration extends IIntegrationBase { + point: IntegrationPoint.DROPDOWN_MENU; + /** Menu item icon */ + icon?: string; + /** Menu item label */ + label: string; + /** Add separator before this item */ + separator?: boolean; + /** Toast config on click */ + toast?: IToastConfig; +} +/** + * Configuration for chat title interaction. + */ +interface ITitleIntegration extends IIntegrationBase { + point: IntegrationPoint.CHAT_TITLE; + /** Interaction type */ + interaction: 'click' | 'dblclick' | 'hover'; + /** Hint text shown on hover */ + hint?: string; + /** Toast config on interaction */ + toast?: IToastConfig; +} +/** + * Toast popup configuration. + */ +interface IToastConfig { + /** Toast title */ + title: string; + /** Badge label and colors */ + badge?: { + text: string; + bgColor: string; + textColor: string; + }; + /** Key-value rows to display */ + rows: IToastRow[]; + /** Auto-dismiss after N milliseconds (default: 6000) */ + duration?: number; +} +/** + * A row in a toast popup. + */ +interface IToastRow { + /** Label (left side) */ + key: string; + /** + * Value (right side). + * Can be a static string or a dynamic expression. + * Dynamic expressions are JS code that runs in the renderer, + * with access to `getStats()` which returns conversation stats. + */ + value: string; + /** If true, `value` is treated as a JS expression */ + dynamic?: boolean; +} +/** + * Metrics available for turn metadata display. + */ +type TurnMetric = 'turnNumber' | 'userCharCount' | 'aiCharCount' | 'codeBlocks' | 'thinkingIndicator' | 'ratio' | 'separator'; +/** + * Union type of all integration configurations. + */ +type IntegrationConfig = IButtonIntegration | ITurnMetaIntegration | IUserBadgeIntegration | IBotActionIntegration | IDropdownIntegration | ITitleIntegration; +/** + * Public interface for the Integration Manager. + */ +interface IIntegrationManager { + /** Register a single integration point */ + register(config: IntegrationConfig): void; + /** Register multiple integration points at once */ + registerMany(configs: IntegrationConfig[]): void; + /** Remove a registered integration by ID */ + unregister(id: string): void; + /** Get all registered integrations */ + getRegistered(): ReadonlyArray; + /** Generate the integration script from all registered configs */ + build(): string; + /** Install the generated script into workbench.html. Returns true if content changed. */ + install(): Promise; + /** Remove the integration from workbench.html */ + uninstall(): Promise; + /** Check if an integration is currently installed */ + isInstalled(): boolean; +} + +/** + * Title Manager — Extension-host API for managing chat titles. + * + * Allows extensions to programmatically rename conversations + * by writing to a data file that the renderer-side title proxy reads. + * + * Also provides a direct localStorage synchronization mechanism + * via the integration script's window.__agSDKTitles API. + * + * @module integration/title-manager + * + * @example + * ```typescript + * const sdk = new AntigravitySDK(context); + * await sdk.initialize(); + * + * // Rename via extension host (writes data file, renderer picks up on next poll) + * sdk.titles.rename('cascade-uuid', 'My Custom Title'); + * + * // Get all custom titles + * const titles = sdk.titles.getAll(); + * + * // Remove a custom title (reverts to auto-generated summary) + * sdk.titles.remove('cascade-uuid'); + * ``` + */ + +/** + * Manages custom conversation titles from the extension host. + * + * Titles are persisted in a JSON file in the workbench directory. + * The renderer-side title proxy reads this file and merges with localStorage. + */ +declare class TitleManager implements IDisposable { + private _titles; + private _dataPath; + private _initialized; + /** + * Initialize with the workbench directory path. + * + * @param workbenchDir - Path to workbench directory where data file is stored + * @param namespace - Extension namespace for file isolation + */ + initialize(workbenchDir: string, namespace?: string): void; + /** + * Check if the manager is initialized. + */ + get isInitialized(): boolean; + /** + * Set a custom title for a conversation. + * + * The title will be displayed in the Agent View title bar + * and conversation list instead of the auto-generated summary. + * + * @param cascadeId - The conversation's cascade ID (UUID) + * @param title - The custom title to display + * + * @example + * ```typescript + * // Rename the active conversation + * const id = sdk.titles.getActiveCascadeId(); + * sdk.titles.rename(id, 'Project Alpha Discussion'); + * ``` + */ + rename(cascadeId: string, title: string): void; + /** + * Get the custom title for a conversation. + * + * @param cascadeId - The conversation's cascade ID + * @returns The custom title, or undefined if no custom title is set + */ + getTitle(cascadeId: string): string | undefined; + /** + * Get all custom titles. + * + * @returns A copy of the titles map (cascadeId -> title) + */ + getAll(): Readonly>; + /** + * Remove a custom title, reverting to the auto-generated summary. + * + * @param cascadeId - The conversation's cascade ID + */ + remove(cascadeId: string): void; + /** + * Remove all custom titles. + */ + clear(): void; + /** + * Get the number of custom titles. + */ + get count(): number; + /** Load titles from the data file */ + private _load; + /** Save titles to the data file */ + private _save; + dispose(): void; +} + +/** + * Integration Manager — Public API for UI integration into Agent View. + * + * Orchestrates ScriptGenerator and WorkbenchPatcher to provide + * a clean, developer-friendly API. + * + * @module integration/integration-manager + * + * @example + * ```typescript + * import { IntegrationManager, IntegrationPoint } from 'antigravity-sdk'; + * + * const integrator = new IntegrationManager(); + * + * integrator.register({ + * id: 'myStats', + * point: IntegrationPoint.TOP_BAR, + * icon: '📊', + * tooltip: 'Show Stats', + * toast: { + * title: 'My Extension Stats', + * rows: [{ key: 'turns:', value: 'Dynamic data here' }], + * }, + * }); + * + * integrator.register({ + * id: 'turnInfo', + * point: IntegrationPoint.TURN_METADATA, + * metrics: ['turnNumber', 'userCharCount', 'separator', 'aiCharCount', 'codeBlocks'], + * }); + * + * await integrator.install(); + * // Restart Antigravity to see changes + * ``` + */ + +/** + * Manages UI integrations into the Antigravity Agent View. + * + * Provides a declarative API to register integration points, + * generates a self-contained JavaScript file, and installs it + * into Antigravity's workbench. + * + * Features: + * - **Theme-aware**: Adapts to dark/light mode automatically + * - **Auto-repair**: Watches workbench.html and re-patches after updates + * - **Dynamic update**: Re-generate script without re-patching workbench.html + */ +declare class IntegrationManager implements IIntegrationManager, IDisposable { + private readonly _configs; + private readonly _generator; + private readonly _patcher; + private readonly _integrity; + private readonly _titles; + private readonly _namespace; + private _watcher; + private _autoRepairDebounce; + private _titleProxyEnabled; + /** + * @param namespace - Unique slug that isolates this extension's files. + * Derived automatically from `context.extension.id` when using AntigravitySDK. + * Multiple SDK-based extensions can coexist without conflicts. + */ + constructor(namespace?: string); + /** + * Register a single integration point. + * + * @throws If an integration with the same ID already exists + */ + register(config: IntegrationConfig): void; + /** + * Register multiple integration points at once. + */ + registerMany(configs: IntegrationConfig[]): void; + /** + * Remove a registered integration by ID. + */ + unregister(id: string): void; + /** + * Get all registered integrations. + */ + getRegistered(): ReadonlyArray; + /** + * Add a button to the top bar (near +, refresh icons). + */ + addTopBarButton(id: string, icon: string, tooltip?: string, toast?: IToastConfig): this; + /** + * Add a button to the top-right corner (before X). + */ + addTopRightButton(id: string, icon: string, tooltip?: string, toast?: IToastConfig): this; + /** + * Add a button next to the send/voice buttons. + */ + addInputButton(id: string, icon: string, tooltip?: string, toast?: IToastConfig): this; + /** + * Add an icon to the bottom icon row (file, terminal, etc.). + */ + addBottomIcon(id: string, icon: string, tooltip?: string, toast?: IToastConfig): this; + /** + * Enable per-turn metadata display. + */ + addTurnMetadata(id: string, metrics: ITurnMetaIntegration['metrics'], clickable?: boolean): this; + /** + * Add character count badges to user messages. + */ + addUserBadges(id: string, display?: IUserBadgeIntegration['display']): this; + /** + * Add an action button next to Good/Bad feedback. + */ + addBotAction(id: string, icon: string, label: string, toast?: IToastConfig): this; + /** + * Add item(s) to the 3-dot dropdown menu. + */ + addDropdownItem(id: string, label: string, icon?: string, toast?: IToastConfig, separator?: boolean): this; + /** + * Enable chat title interaction. + */ + addTitleInteraction(id: string, interaction?: ITitleIntegration['interaction'], hint?: string, toast?: IToastConfig): this; + /** + * Enable the title proxy feature. + * + * Adds renderer-side code that intercepts the summaries provider + * and injects custom chat titles. Uses structural matching to find + * the provider (obfuscation-safe). + * + * After enabling, call `install()` or `updateScript()` to apply. + * + * @example + * ```typescript + * const sdk = new AntigravitySDK(context); + * await sdk.initialize(); + * + * sdk.integration.enableTitleProxy(); + * await sdk.integration.install(); + * + * // Now rename from extension host: + * sdk.integration.titles.rename(cascadeId, 'My Custom Title'); + * ``` + */ + enableTitleProxy(): this; + /** + * Access the title manager for programmatic title control. + * + * Requires `enableTitleProxy()` to be called first. + * + * @example + * ```typescript + * sdk.integration.titles.rename(cascadeId, 'My Title'); + * sdk.integration.titles.remove(cascadeId); + * const all = sdk.integration.titles.getAll(); + * ``` + */ + get titles(): TitleManager; + /** + * Generate the integration script from all registered configs. + * + * If title proxy is enabled, appends the title proxy renderer code. + * + * @returns Complete JavaScript code as a string + */ + build(): string; + /** + * Install the generated script into workbench.html. + * + * For seamless hot-reload behavior, use `installSeamless()` instead. + * + * @returns true if the script content actually changed on disk + */ + install(): Promise; + /** + * Seamless install — handles everything automatically. + * + * This is the **recommended** install method for extension developers. + * It handles the entire lifecycle: + * + * 1. **First install:** Writes script + patches HTML + prompts user to reload + * 2. **Update:** Compares content, if changed → auto-reloads window (no prompt) + * 3. **No change:** Does nothing + * + * The developer never needs to think about reload. + * + * @param executeCommand - Function to execute VS Code commands + * (pass `vscode.commands.executeCommand` or equivalent) + * + * @example + * ```typescript + * const sdk = new AntigravitySDK(context); + * await sdk.initialize(); + * + * sdk.integration.enableTitleProxy(); + * // That's it. SDK handles install, reload, everything. + * await sdk.integration.installSeamless( + * (cmd) => vscode.commands.executeCommand(cmd), + * (msg, ...items) => vscode.window.showInformationMessage(msg, ...items), + * ); + * ``` + */ + installSeamless(executeCommand: (command: string) => Thenable, showMessage?: (message: string, ...items: string[]) => Thenable): Promise; + /** + * Remove the integration from workbench.html. + * + * ⚠️ Requires Antigravity restart to take effect. + */ + uninstall(): Promise; + /** + * Check if an integration is currently installed. + */ + isInstalled(): boolean; + /** + * Signal that the extension is active. + * + * Call this in your extension's `activate()` function. + * The integration script checks for this heartbeat; + * if it's missing or stale (>48h), the script won't start. + * + * This prevents orphaned integrations from running after + * an extension is disabled or uninstalled. + * + * @example + * ```typescript + * export function activate(context: vscode.ExtensionContext) { + * const sdk = new AntigravitySDK(context); + * sdk.integration.signalActive(); + * // ... + * } + * ``` + */ + signalActive(): void; + /** + * Re-generate and overwrite the integration script without re-patching workbench.html. + * + * Use this after registering/unregistering integration points at runtime. + * The script file is updated in-place; the next Antigravity restart + * will pick up the changes. workbench.html `, + this._markerEnd + ].join("\n"); + html = html.replace("", `${scriptTag} +`); + fs2__namespace.writeFileSync(this._workbenchHtml, html, "utf8"); + const titlesPath = path2__namespace.join(this._workbenchDir, `ag-sdk-titles-${this._slug}.json`); + if (!fs2__namespace.existsSync(titlesPath)) { + fs2__namespace.writeFileSync(titlesPath, "{}", "utf8"); + } + } + /** + * Remove the integration. + * + * 1. Removes the