diff --git a/CHANGELOG.md b/CHANGELOG.md
index 766c7948..be4bd5b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## [3.25.0](https://github.com/breaking-brake/cc-wf-studio/compare/v3.24.1...v3.25.0) (2026-02-21)
+
+### Features
+
+* add Antigravity (Google VSCode fork) provider support ([#602](https://github.com/breaking-brake/cc-wf-studio/issues/602)) ([08c2100](https://github.com/breaking-brake/cc-wf-studio/commit/08c21001b06a8aec694ef5dd27e50ce8f12ce9a7))
+
## [3.24.1](https://github.com/breaking-brake/cc-wf-studio/compare/v3.24.0...v3.24.1) (2026-02-21)
### Improvements
diff --git a/README.md b/README.md
index cb55712a..a0c0638d 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
Visual Workflow Editor for AI Agents
-
+
| Agent | Export Format | Requires |
|-------|--------------|----------|
@@ -30,6 +30,7 @@
| OpenAI Codex CLI | `.codex/skills/` | [Codex CLI](https://github.com/openai/codex) |
| Roo Code | `.roo/skills/` | [Roo Code](https://marketplace.visualstudio.com/items?itemName=RooVeterinaryInc.roo-cline) |
| Gemini CLI | `.gemini/skills/` | [Gemini CLI](https://github.com/google-gemini/gemini-cli) |
+| Antigravity | `.agent/skills/` | [Antigravity](https://antigravity.google/) |
> **Note:** Agents other than Claude Code require activation from Toolbar's **More** menu.
@@ -94,7 +95,7 @@
### Edit with AI
- Click Edit with AI
button in the toolbar to generate or refine workflows with natural language
-- **Native with MCP Server**: Click an AI agent button (Claude Code, Copilot Chat, Copilot CLI, Codex, Roo Code) in the Edit with AI panel to launch native AI editing. The MCP server starts automatically behind the scenes.
+- **Native with MCP Server**: Click an AI agent button in the Edit with AI panel to launch native AI editing. The MCP server starts automatically behind the scenes.
```mermaid
sequenceDiagram
diff --git a/docs/ai-coding-tools-config-reference.md b/docs/ai-coding-tools-config-reference.md
index ddbcc4f6..55d42644 100644
--- a/docs/ai-coding-tools-config-reference.md
+++ b/docs/ai-coding-tools-config-reference.md
@@ -9,6 +9,7 @@ Created by referencing official documentation for each tool.
|------|-------|--------|------------------|--------------|-----|--------|
| Claude Code | Project
User | Project
User | Project
User | Project
User | Project
User | Project |
| Gemini CLI | Project
User | Project
User | Project
User | - | Project
User | Project |
+| Antigravity | Project | Project
User | Workflows | Agent mode | Project | - |
| Roo Code | Project
Global | Project
Global | Project
Global | Project
Global | Project
Global | Project |
| VSCode Copilot Chat | Project
User | Project
User | Project
User | Project | Project
User | - |
| Copilot CLI | Project | Project
Global | - | Project
Global | Global | - |
@@ -361,6 +362,186 @@ MCP servers are configured in `settings.json` under `mcpServers` key.
---
+## Antigravity (Google)
+
+Antigravity is a Google-made VSCode fork with a built-in AI agent called **Cascade**.
+
+> **Note:** This section is based on reverse engineering of Antigravity v1.107.0 (app bundle analysis). No official public documentation is available.
+>
+> - Extension ID (built-in): `google.antigravity`
+> - Internal codename: Jetski
+> - App location: `/Applications/Antigravity.app`
+> - Config directory: `~/Library/Application Support/Antigravity/`
+
+### VSCode Commands (AI Agent Interaction)
+
+These commands can be used via `vscode.commands.executeCommand()` to interact with Antigravity's Cascade AI.
+
+#### Chat / Agent Launch
+
+| Command | Description |
+|---------|-------------|
+| `antigravity.sendPromptToAgentPanel` | Send a prompt to the Agent panel |
+| `antigravity.openAgent` | Open the Agent side panel |
+| `antigravity.openChatView` | Open the Chat view |
+| `antigravity.startNewConversation` | Start a new conversation |
+| `antigravity.sendTextToChat` | Send text to Chat |
+| `antigravity.sendChatActionMessage` | Send a chat action message |
+| `antigravity.sendTerminalToChat` | Send terminal content to Chat |
+| `antigravity.sendTerminalToSidePanel` | Send terminal content to side panel |
+| `antigravity.enableAgentMode` | Enable Agent mode |
+| `antigravity.initializeAgent` | Initialize the Agent |
+| `antigravity.executeCascadeAction` | Execute a Cascade action |
+
+#### Standard VSCode Chat API (also supported)
+
+| Command | Description |
+|---------|-------------|
+| `workbench.action.chat.open` | Open chat (supports `{ mode: 'agent', query: '...' }`) |
+| `workbench.action.chat.newChat` | Create a new chat session |
+
+#### Agent Step Control
+
+| Command | Description |
+|---------|-------------|
+| `antigravity.agent.acceptAgentStep` | Accept an agent step |
+| `antigravity.agent.rejectAgentStep` | Reject an agent step |
+| `antigravity.agent.manageAnnotations` | Manage agent annotations |
+
+#### Workflow / Rules
+
+| Command | Description |
+|---------|-------------|
+| `antigravity.createWorkflow` | Create a workflow |
+| `antigravity.createGlobalWorkflow` | Create a global workflow |
+| `antigravity.createRule` | Create a rule |
+| `antigravity.openGlobalRules` | Open global rules |
+
+#### Other Notable Commands
+
+| Command | Description |
+|---------|-------------|
+| `antigravity.openMcpConfigFile` | Open MCP config file |
+| `antigravity.pollMcpServerStates` | Poll MCP server states |
+| `antigravity.generateCommitMessage` | Generate commit message |
+| `antigravity.openBrowser` | Open built-in browser |
+| `antigravity.getCascadePluginTemplate` | Get Cascade plugin template |
+| `antigravity.login` | Log in to IDE |
+
+### Built-in Extensions
+
+| Extension | Description |
+|-----------|-------------|
+| `antigravity` | Core AI features (Cascade, completions, agent) |
+| `antigravity-code-executor` | Execute generated code from Cascade |
+| `antigravity-browser-launcher` | Built-in browser launcher |
+| `antigravity-dev-containers` | Dev Containers support |
+| `antigravity-remote-openssh` | Remote SSH support |
+| `antigravity-remote-wsl` | Remote WSL support |
+
+### Rules
+
+| Scope | Path | Description |
+|-------|------|-------------|
+| **Project** | `./.agent/rules/**/*.md` or `./.agents/rules/**/*.md` | Agent rules (markdown files) |
+
+Rules files use the header `# antigravity rules`.
+
+> **Note:** `antigravity.createRule` command is available for rule creation. `antigravity.openGlobalRules` opens global rules.
+
+### Skills (Claude Skills互換)
+
+Antigravityは **`.agent/skills/` ディレクトリ** からスキルを読み込む(`chat.useClaudeSkills` 設定で有効化)。Claude Code の SKILL.md と同一フォーマット。
+
+| Scope | Path | Description |
+|-------|------|-------------|
+| **Project** | `./.agent/skills/{skill-name}/SKILL.md` | プロジェクトスキル |
+
+**検出ロジック:**
+1. `.agent/skills/` ディレクトリを探索
+2. 各サブディレクトリ内の `SKILL.md` を検出
+3. Frontmatter の `name` と `description` をシステムプロンプトに注入
+4. ユーザーのタスクがスキルのドメインに一致すると、スキル内容が会話に追加される
+
+**Frontmatter Schema:**
+```yaml
+---
+name: skill-name # Required
+description: Skill description # Required
+---
+```
+
+> **Note:** `chat.useClaudeSkills` 設定(experimental)で切り替え可能。Claude Code の SKILL.md と同一フォーマット。
+
+### MCP
+
+Antigravity uses a **global MCP configuration** at `~/.gemini/antigravity/mcp_config.json`.
+
+| Scope | Path | Description |
+|-------|------|-------------|
+| **Global** | `~/.gemini/antigravity/mcp_config.json` | Global MCP configuration |
+
+**JSON Schema:**
+```json
+{
+ "mcpServers": {
+ "server-name": {
+ "command": "npx",
+ "args": ["-y", "package-name"],
+ "env": {}
+ }
+ }
+}
+```
+
+> **Note:** Uses `mcpServers` key (same as Claude Code), NOT `servers`.
+
+### Cascade Configuration
+
+Cascade has several configuration keys found in the workbench:
+
+| Key | Description |
+|-----|-------------|
+| `cascade_config` | General Cascade configuration |
+| `cascade_model_config_data` | Model configuration |
+| `cascade_allowed_commands` | Allowed shell commands |
+| `cascade_denied_commands` | Denied shell commands |
+| `cascade_auto_execution_policy` | Auto-execution policy for commands |
+| `cascade_browser_mode` | Browser mode settings |
+| `cascade_web_search` | Web search toggle |
+| `cascade_plugins` | Cascade plugins |
+| `cascade_planner_mode` | Planner mode toggle |
+| `cascade_memory_summary` | Memory/conversation summary |
+| `cascade_init_prompt` | Initial prompt for Cascade |
+
+### CLI
+
+| Item | Path |
+|------|------|
+| **Binary** | `~/.antigravity/antigravity/bin/antigravity` |
+| **URI Scheme** | `antigravity://` (deep links) |
+
+### Integration Strategy for cc-wf-studio
+
+**Execution pattern:** Closest to **Copilot Chat** (VSCode command-based).
+
+```typescript
+// Recommended launch pattern
+await vscode.commands.executeCommand('antigravity.sendPromptToAgentPanel', prompt);
+
+// Fallback: standard VSCode Chat API
+await vscode.commands.executeCommand('workbench.action.chat.open', {
+ mode: 'agent',
+ query: prompt,
+});
+```
+
+**MCP config:** Shares `.vscode/mcp.json` with Copilot Chat (same `servers` key).
+
+**Skill file location:** `.claude/skills/{skill-name}/SKILL.md`(Claude Codeと完全互換)。`chat.useClaudeSkills` 設定で有効化。
+
+---
+
## VSCode Copilot Chat
GitHub Copilot Chat functionality within VSCode.
@@ -893,6 +1074,12 @@ Project Root/
│
├── .geminiignore # Gemini CLI (ignore)
│
+├── .agent/
+│ ├── rules/**/*.md # Antigravity (agent rules)
+│ └── skills/{name}/SKILL.md # Antigravity (skills)
+├── .agents/
+│ └── rules/**/*.md # Antigravity (agent rules, alternative)
+│
├── .github/
│ ├── copilot-instructions.md # VSCode Copilot Chat, Copilot CLI (root rule)
│ ├── instructions/*.instructions.md # VSCode Copilot Chat, Copilot CLI (modular rules)
@@ -937,7 +1124,9 @@ User Home (~)/
│ ├── settings.json # Gemini CLI (user settings + MCP)
│ ├── commands/*.toml # Gemini CLI (user custom commands)
│ ├── skills/{name}/SKILL.md # Gemini CLI (user skills)
-│ └── extensions/{name}/ # Gemini CLI (installed extensions)
+│ ├── extensions/{name}/ # Gemini CLI (installed extensions)
+│ └── antigravity/
+│ └── mcp_config.json # Antigravity (global MCP)
│
├── .copilot/
│ ├── config.json # Copilot CLI (main config)
@@ -986,6 +1175,7 @@ User Home (~)/
## References
+- Antigravity: No official public documentation. Information reverse-engineered from app bundle v1.107.0.
- [Claude Code Documentation](https://code.claude.com/docs/en)
- [Claude Code Settings](https://code.claude.com/docs/en/settings)
- [Claude Code Skills](https://code.claude.com/docs/en/skills)
diff --git a/package-lock.json b/package-lock.json
index 15a3fa82..81b3a357 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cc-wf-studio",
- "version": "3.24.1",
+ "version": "3.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cc-wf-studio",
- "version": "3.24.1",
+ "version": "3.25.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.26.0",
diff --git a/package.json b/package.json
index 8d5449eb..a34430ff 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "cc-wf-studio",
"displayName": "Claude Code Workflow Studio",
- "description": "Visual Workflow Editor for Claude Code, GitHub Copilot, Codex CLI, Roo Code, and Gemini CLI",
- "version": "3.24.1",
+ "description": "Visual Workflow Editor for Claude Code, GitHub Copilot, Codex CLI, Roo Code, Gemini CLI, and Antigravity",
+ "version": "3.25.0",
"publisher": "breaking-brake",
"icon": "resources/icon.png",
"repository": {
@@ -19,7 +19,8 @@
"codex",
"copilot",
"roo",
- "gemini"
+ "gemini",
+ "antigravity"
],
"engines": {
"vscode": "^1.80.0"
diff --git a/src/extension/commands/antigravity-handlers.ts b/src/extension/commands/antigravity-handlers.ts
new file mode 100644
index 00000000..6863581b
--- /dev/null
+++ b/src/extension/commands/antigravity-handlers.ts
@@ -0,0 +1,237 @@
+/**
+ * Claude Code Workflow Studio - Antigravity Integration Handlers
+ *
+ * Handles Export/Run for Google Antigravity (Cascade) integration
+ */
+
+import * as vscode from 'vscode';
+import type {
+ AntigravityOperationFailedPayload,
+ ExportForAntigravityPayload,
+ ExportForAntigravitySuccessPayload,
+ RunForAntigravityPayload,
+ RunForAntigravitySuccessPayload,
+} from '../../shared/types/messages';
+import {
+ isAntigravityInstalled,
+ startAntigravityTask,
+} from '../services/antigravity-extension-service';
+import {
+ checkExistingAntigravitySkill,
+ exportWorkflowAsAntigravitySkill,
+} from '../services/antigravity-skill-export-service';
+import type { FileService } from '../services/file-service';
+import {
+ hasNonStandardSkills,
+ promptAndNormalizeSkills,
+} from '../services/skill-normalization-service';
+
+/**
+ * Handle Export for Antigravity request
+ *
+ * Exports workflow to Skills format (.agent/skills/name/SKILL.md)
+ *
+ * @param fileService - File service instance
+ * @param webview - Webview for sending responses
+ * @param payload - Export payload
+ * @param requestId - Optional request ID for response correlation
+ */
+export async function handleExportForAntigravity(
+ fileService: FileService,
+ webview: vscode.Webview,
+ payload: ExportForAntigravityPayload,
+ requestId?: string
+): Promise {
+ try {
+ const { workflow } = payload;
+
+ // Check for existing skill and ask for confirmation
+ const existingSkillPath = await checkExistingAntigravitySkill(workflow, fileService);
+ if (existingSkillPath) {
+ const result = await vscode.window.showWarningMessage(
+ `Skill already exists: ${existingSkillPath}\n\nOverwrite?`,
+ { modal: true },
+ 'Overwrite',
+ 'Cancel'
+ );
+ if (result !== 'Overwrite') {
+ webview.postMessage({
+ type: 'EXPORT_FOR_ANTIGRAVITY_CANCELLED',
+ requestId,
+ });
+ return;
+ }
+ }
+
+ // Export workflow as skill to .agent/skills/{name}/SKILL.md
+ const exportResult = await exportWorkflowAsAntigravitySkill(workflow, fileService);
+
+ if (!exportResult.success) {
+ const failedPayload: AntigravityOperationFailedPayload = {
+ errorCode: 'EXPORT_FAILED',
+ errorMessage: exportResult.errors?.join(', ') || 'Failed to export workflow as skill',
+ timestamp: new Date().toISOString(),
+ };
+ webview.postMessage({
+ type: 'EXPORT_FOR_ANTIGRAVITY_FAILED',
+ requestId,
+ payload: failedPayload,
+ });
+ return;
+ }
+
+ // Send success response
+ const successPayload: ExportForAntigravitySuccessPayload = {
+ skillName: exportResult.skillName,
+ skillPath: exportResult.skillPath,
+ timestamp: new Date().toISOString(),
+ };
+
+ webview.postMessage({
+ type: 'EXPORT_FOR_ANTIGRAVITY_SUCCESS',
+ requestId,
+ payload: successPayload,
+ });
+
+ vscode.window.showInformationMessage(
+ `Exported workflow as Antigravity skill: ${exportResult.skillPath}`
+ );
+ } catch (error) {
+ const failedPayload: AntigravityOperationFailedPayload = {
+ errorCode: 'UNKNOWN_ERROR',
+ errorMessage: error instanceof Error ? error.message : 'Unknown error',
+ timestamp: new Date().toISOString(),
+ };
+ webview.postMessage({
+ type: 'EXPORT_FOR_ANTIGRAVITY_FAILED',
+ requestId,
+ payload: failedPayload,
+ });
+ }
+}
+
+/**
+ * Handle Run for Antigravity request
+ *
+ * Exports workflow to Skills format and runs it via Antigravity (Cascade)
+ *
+ * @param fileService - File service instance
+ * @param webview - Webview for sending responses
+ * @param payload - Run payload
+ * @param requestId - Optional request ID for response correlation
+ */
+export async function handleRunForAntigravity(
+ fileService: FileService,
+ webview: vscode.Webview,
+ payload: RunForAntigravityPayload,
+ requestId?: string
+): Promise {
+ try {
+ const { workflow } = payload;
+
+ // Step 0.5: Normalize skills (copy non-standard skills to .claude/skills/)
+ // For Antigravity, .agent/skills/ is the native directory
+ if (hasNonStandardSkills(workflow, 'antigravity')) {
+ const normalizeResult = await promptAndNormalizeSkills(workflow, 'antigravity');
+
+ if (!normalizeResult.success) {
+ if (normalizeResult.cancelled) {
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_CANCELLED',
+ requestId,
+ });
+ return;
+ }
+ throw new Error(normalizeResult.error || 'Failed to copy skills to .claude/skills/');
+ }
+
+ // Log normalized skills
+ if (normalizeResult.normalizedSkills && normalizeResult.normalizedSkills.length > 0) {
+ console.log(
+ `[Antigravity] Copied ${normalizeResult.normalizedSkills.length} skill(s) to .claude/skills/`
+ );
+ }
+ }
+
+ // Step 1: Check for existing skill and ask for confirmation
+ const existingSkillPath = await checkExistingAntigravitySkill(workflow, fileService);
+ if (existingSkillPath) {
+ const result = await vscode.window.showWarningMessage(
+ `Skill already exists: ${existingSkillPath}\n\nOverwrite?`,
+ { modal: true },
+ 'Overwrite',
+ 'Cancel'
+ );
+ if (result !== 'Overwrite') {
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_CANCELLED',
+ requestId,
+ });
+ return;
+ }
+ }
+
+ // Step 2: Export workflow as skill to .claude/skills/{name}/SKILL.md
+ const exportResult = await exportWorkflowAsAntigravitySkill(workflow, fileService);
+
+ if (!exportResult.success) {
+ const failedPayload: AntigravityOperationFailedPayload = {
+ errorCode: 'EXPORT_FAILED',
+ errorMessage: exportResult.errors?.join(', ') || 'Failed to export workflow as skill',
+ timestamp: new Date().toISOString(),
+ };
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_FAILED',
+ requestId,
+ payload: failedPayload,
+ });
+ return;
+ }
+
+ // Step 3: Check if Antigravity is installed
+ if (!isAntigravityInstalled()) {
+ const failedPayload: AntigravityOperationFailedPayload = {
+ errorCode: 'ANTIGRAVITY_NOT_INSTALLED',
+ errorMessage: 'Antigravity extension is not installed.',
+ timestamp: new Date().toISOString(),
+ };
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_FAILED',
+ requestId,
+ payload: failedPayload,
+ });
+ return;
+ }
+
+ // Step 4: Launch Cascade with the skill
+ await startAntigravityTask(exportResult.skillName);
+
+ // Send success response
+ const successPayload: RunForAntigravitySuccessPayload = {
+ workflowName: workflow.name,
+ antigravityOpened: true,
+ timestamp: new Date().toISOString(),
+ };
+
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_SUCCESS',
+ requestId,
+ payload: successPayload,
+ });
+
+ vscode.window.showInformationMessage(
+ `Running workflow via Antigravity (Cascade): ${workflow.name}`
+ );
+ } catch (error) {
+ const failedPayload: AntigravityOperationFailedPayload = {
+ errorCode: 'UNKNOWN_ERROR',
+ errorMessage: error instanceof Error ? error.message : 'Unknown error',
+ timestamp: new Date().toISOString(),
+ };
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_FAILED',
+ requestId,
+ payload: failedPayload,
+ });
+ }
+}
diff --git a/src/extension/commands/open-editor.ts b/src/extension/commands/open-editor.ts
index 7ad14783..7673591d 100644
--- a/src/extension/commands/open-editor.ts
+++ b/src/extension/commands/open-editor.ts
@@ -20,6 +20,10 @@ import type {
import { getMcpServerManager, log } from '../extension';
import { translate } from '../i18n/i18n-service';
import { generateAndRunAiEditingSkill } from '../services/ai-editing-skill-service';
+import {
+ openAntigravityMcpSettings,
+ startAntigravityTask,
+} from '../services/antigravity-extension-service';
import { cancelGeneration } from '../services/claude-code-service';
import { FileService } from '../services/file-service';
import {
@@ -34,6 +38,7 @@ import { migrateWorkflow } from '../utils/migrate-workflow';
import { SlackTokenManager } from '../utils/slack-token-manager';
import { validateWorkflowFile } from '../utils/workflow-validator';
import { getWebviewContent } from '../webview-content';
+import { handleExportForAntigravity, handleRunForAntigravity } from './antigravity-handlers';
import { handleExportForCodexCli, handleRunForCodexCli } from './codex-handlers';
import {
handleExportForCopilot,
@@ -561,6 +566,50 @@ export function registerOpenEditorCommand(
}
break;
+ case 'EXPORT_FOR_ANTIGRAVITY':
+ // Export workflow for Antigravity (Skills format)
+ if (message.payload?.workflow) {
+ await handleExportForAntigravity(
+ fileService,
+ webview,
+ message.payload,
+ message.requestId
+ );
+ } else {
+ webview.postMessage({
+ type: 'EXPORT_FOR_ANTIGRAVITY_FAILED',
+ requestId: message.requestId,
+ payload: {
+ errorCode: 'UNKNOWN_ERROR',
+ errorMessage: 'Workflow is required',
+ timestamp: new Date().toISOString(),
+ },
+ });
+ }
+ break;
+
+ case 'RUN_FOR_ANTIGRAVITY':
+ // Run workflow for Antigravity (via Cascade)
+ if (message.payload?.workflow) {
+ await handleRunForAntigravity(
+ fileService,
+ webview,
+ message.payload,
+ message.requestId
+ );
+ } else {
+ webview.postMessage({
+ type: 'RUN_FOR_ANTIGRAVITY_FAILED',
+ requestId: message.requestId,
+ payload: {
+ errorCode: 'UNKNOWN_ERROR',
+ errorMessage: 'Workflow is required',
+ timestamp: new Date().toISOString(),
+ },
+ });
+ }
+ break;
+
case 'LOAD_WORKFLOW_LIST':
// Load workflow list
await loadWorkflowList(fileService, webview, message.requestId);
@@ -1383,6 +1432,18 @@ export function registerOpenEditorCommand(
workspacePath
);
+ // For Antigravity, pause and let the user manually refresh MCP
+ if (launchPayload.provider === 'antigravity') {
+ webview.postMessage({
+ type: 'ANTIGRAVITY_MCP_REFRESH_NEEDED',
+ requestId: message.requestId,
+ });
+ log('INFO', 'Antigravity MCP refresh needed, waiting for user', {
+ port: serverPort,
+ });
+ break;
+ }
+
webview.postMessage({
type: 'LAUNCH_AI_AGENT_SUCCESS',
requestId: message.requestId,
@@ -1413,6 +1474,36 @@ export function registerOpenEditorCommand(
break;
}
+ case 'OPEN_ANTIGRAVITY_MCP_SETTINGS': {
+ await openAntigravityMcpSettings();
+ break;
+ }
+
+ case 'CONFIRM_ANTIGRAVITY_CASCADE_LAUNCH': {
+ try {
+ await startAntigravityTask('cc-workflow-ai-editor');
+ webview.postMessage({
+ type: 'LAUNCH_AI_AGENT_SUCCESS',
+ requestId: message.requestId,
+ payload: {
+ provider: 'antigravity',
+ timestamp: new Date().toISOString(),
+ },
+ });
+ } catch (error) {
+ webview.postMessage({
+ type: 'LAUNCH_AI_AGENT_FAILED',
+ requestId: message.requestId,
+ payload: {
+ errorMessage:
+ error instanceof Error ? error.message : 'Failed to launch Antigravity',
+ timestamp: new Date().toISOString(),
+ },
+ });
+ }
+ break;
+ }
+
default:
console.warn('Unknown message type:', message);
}
diff --git a/src/extension/services/ai-editing-skill-service.ts b/src/extension/services/ai-editing-skill-service.ts
index 3d7f48ba..f080a0cf 100644
--- a/src/extension/services/ai-editing-skill-service.ts
+++ b/src/extension/services/ai-editing-skill-service.ts
@@ -10,6 +10,7 @@ import * as fs from 'node:fs';
import * as path from 'node:path';
import * as vscode from 'vscode';
import { log } from '../extension';
+import { isAntigravityInstalled } from './antigravity-extension-service';
import { isRooCodeInstalled, startRooCodeTask } from './roo-code-extension-service';
export type AiEditingProvider =
@@ -18,7 +19,8 @@ export type AiEditingProvider =
| 'copilot-chat'
| 'codex'
| 'roo-code'
- | 'gemini';
+ | 'gemini'
+ | 'antigravity';
const SKILL_NAME = 'cc-workflow-ai-editor';
@@ -39,6 +41,8 @@ function getSkillDestination(provider: AiEditingProvider, workingDirectory: stri
return path.join(workingDirectory, '.roo', 'skills', SKILL_NAME, 'SKILL.md');
case 'gemini':
return path.join(workingDirectory, '.gemini', 'skills', SKILL_NAME, 'SKILL.md');
+ case 'antigravity':
+ return path.join(workingDirectory, '.agent', 'skills', SKILL_NAME, 'SKILL.md');
}
}
@@ -142,6 +146,15 @@ async function launchProvider(
terminal.sendText(`gemini -i ":skill ${SKILL_NAME}"`);
break;
}
+
+ case 'antigravity': {
+ // For Antigravity, only check installation here.
+ // Launch is handled separately after MCP refresh dialog in open-editor.ts.
+ if (!isAntigravityInstalled()) {
+ throw new Error('Antigravity extension is not installed.');
+ }
+ break;
+ }
}
}
diff --git a/src/extension/services/antigravity-extension-service.ts b/src/extension/services/antigravity-extension-service.ts
new file mode 100644
index 00000000..a9aebdee
--- /dev/null
+++ b/src/extension/services/antigravity-extension-service.ts
@@ -0,0 +1,67 @@
+/**
+ * Claude Code Workflow Studio - Antigravity Extension Service
+ *
+ * Wrapper for Antigravity (Google VSCode fork) Extension.
+ * Uses VSCode commands to launch Cascade with skill invocation.
+ */
+
+import * as vscode from 'vscode';
+
+const ANTIGRAVITY_EXTENSION_ID = 'google.antigravity';
+
+/**
+ * Check if Antigravity extension is installed
+ *
+ * @returns True if Antigravity extension is installed
+ */
+export function isAntigravityInstalled(): boolean {
+ return vscode.extensions.getExtension(ANTIGRAVITY_EXTENSION_ID) !== undefined;
+}
+
+/**
+ * Open Antigravity's MCP server management page
+ */
+export async function openAntigravityMcpSettings(): Promise {
+ try {
+ await vscode.commands.executeCommand('antigravity.openConfigurePluginsPage');
+ } catch {
+ // Best-effort
+ }
+}
+
+/**
+ * Start a task in Antigravity via Cascade
+ *
+ * Attempts to open Cascade in agent mode with the given skill name.
+ * Primary: workbench.action.chat.open with agent mode
+ * Fallback: antigravity.sendPromptToAgentPanel
+ *
+ * @param skillName - Skill name to invoke (e.g., "my-workflow")
+ * @returns True if the task was started successfully
+ */
+export async function startAntigravityTask(skillName: string): Promise {
+ const extension = vscode.extensions.getExtension(ANTIGRAVITY_EXTENSION_ID);
+ if (!extension) {
+ return false;
+ }
+
+ if (!extension.isActive) {
+ await extension.activate();
+ }
+
+ const prompt = `/${skillName}`;
+
+ try {
+ // Primary: Open Cascade chat in agent mode with skill invocation
+ await vscode.commands.executeCommand('workbench.action.chat.open', prompt);
+ return true;
+ } catch {
+ // Fallback: Try alternative command
+ try {
+ await vscode.commands.executeCommand('antigravity.sendPromptToAgentPanel', prompt);
+ return true;
+ } catch {
+ return false;
+ }
+ }
+}
diff --git a/src/extension/services/antigravity-skill-export-service.ts b/src/extension/services/antigravity-skill-export-service.ts
new file mode 100644
index 00000000..23f344ca
--- /dev/null
+++ b/src/extension/services/antigravity-skill-export-service.ts
@@ -0,0 +1,132 @@
+/**
+ * Claude Code Workflow Studio - Antigravity Skill Export Service
+ *
+ * Handles workflow export to Antigravity Skills format (.agent/skills/name/SKILL.md)
+ * Antigravity reads skills from .agent/skills/ directory.
+ */
+
+import * as path from 'node:path';
+import type { Workflow } from '../../shared/types/workflow-definition';
+import { nodeNameToFileName } from './export-service';
+import type { FileService } from './file-service';
+import {
+ generateExecutionInstructions,
+ generateMermaidFlowchart,
+} from './workflow-prompt-generator';
+
+/**
+ * Antigravity skill export result
+ */
+export interface AntigravitySkillExportResult {
+ success: boolean;
+ skillPath: string;
+ skillName: string;
+ errors?: string[];
+}
+
+/**
+ * Generate SKILL.md content from workflow for Antigravity
+ *
+ * @param workflow - Workflow to convert
+ * @returns SKILL.md content as string
+ */
+export function generateAntigravitySkillContent(workflow: Workflow): string {
+ const skillName = nodeNameToFileName(workflow.name);
+
+ // Generate description from workflow metadata or create default
+ const description =
+ workflow.metadata?.description ||
+ `Execute the "${workflow.name}" workflow. This skill guides through a structured workflow with defined steps and decision points.`;
+
+ // Generate YAML frontmatter
+ const frontmatter = `---
+name: ${skillName}
+description: ${description}
+---`;
+
+ // Generate Mermaid flowchart
+ const mermaidContent = generateMermaidFlowchart({
+ nodes: workflow.nodes,
+ connections: workflow.connections,
+ });
+
+ // Generate execution instructions
+ const instructions = generateExecutionInstructions(workflow, {
+ provider: 'antigravity',
+ });
+
+ // Compose SKILL.md body
+ const body = `# ${workflow.name}
+
+## Workflow Diagram
+
+${mermaidContent}
+
+## Execution Instructions
+
+${instructions}`;
+
+ return `${frontmatter}\n\n${body}`;
+}
+
+/**
+ * Check if Antigravity skill already exists
+ *
+ * @param workflow - Workflow to check
+ * @param fileService - File service instance
+ * @returns Path to existing skill file, or null if not exists
+ */
+export async function checkExistingAntigravitySkill(
+ workflow: Workflow,
+ fileService: FileService
+): Promise {
+ const workspacePath = fileService.getWorkspacePath();
+ const skillName = nodeNameToFileName(workflow.name);
+ const skillPath = path.join(workspacePath, '.agent', 'skills', skillName, 'SKILL.md');
+
+ if (await fileService.fileExists(skillPath)) {
+ return skillPath;
+ }
+ return null;
+}
+
+/**
+ * Export workflow as Antigravity Skill
+ *
+ * Exports to .claude/skills/{name}/SKILL.md
+ *
+ * @param workflow - Workflow to export
+ * @param fileService - File service instance
+ * @returns Export result
+ */
+export async function exportWorkflowAsAntigravitySkill(
+ workflow: Workflow,
+ fileService: FileService
+): Promise {
+ try {
+ const workspacePath = fileService.getWorkspacePath();
+ const skillName = nodeNameToFileName(workflow.name);
+ const skillDir = path.join(workspacePath, '.agent', 'skills', skillName);
+ const skillPath = path.join(skillDir, 'SKILL.md');
+
+ // Ensure directory exists
+ await fileService.createDirectory(skillDir);
+
+ // Generate and write SKILL.md content
+ const content = generateAntigravitySkillContent(workflow);
+ await fileService.writeFile(skillPath, content);
+
+ return {
+ success: true,
+ skillPath,
+ skillName,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ skillPath: '',
+ skillName: '',
+ errors: [error instanceof Error ? error.message : 'Unknown error'],
+ };
+ }
+}
diff --git a/src/extension/services/mcp-config-reader.ts b/src/extension/services/mcp-config-reader.ts
index d526586d..f6900d1a 100644
--- a/src/extension/services/mcp-config-reader.ts
+++ b/src/extension/services/mcp-config-reader.ts
@@ -28,6 +28,9 @@
*
* Roo Code:
* - /.roo/mcp.json (project-level)
+ *
+ * Antigravity:
+ * - ~/.gemini/antigravity/mcp_config.json (user-level, uses 'serverUrl' for HTTP)
*/
import * as fs from 'node:fs';
@@ -37,6 +40,7 @@ import { parse as parseToml } from 'smol-toml';
import type { McpConfigSource } from '../../shared/types/mcp-node';
import { log } from '../extension';
import {
+ getAntigravityUserMcpConfigPath,
getCodexUserMcpConfigPath,
getCopilotUserMcpConfigPath,
getGeminiProjectMcpConfigPath,
@@ -317,6 +321,77 @@ function readRooMcpConfig(configPath: string): Record |
}
}
+/**
+ * Read Antigravity MCP config (~/.gemini/antigravity/mcp_config.json)
+ *
+ * Format: { "mcpServers": { "name": { "serverUrl": "..." } } }
+ * Note: Antigravity uses 'serverUrl' instead of 'url' for HTTP transport.
+ * It also supports standard 'command'/'args' for stdio transport.
+ *
+ * @param configPath - Path to mcp_config.json
+ * @returns MCP servers configuration (normalized) or null if not found
+ */
+function readAntigravityMcpConfig(configPath: string): Record | null {
+ try {
+ const content = fs.readFileSync(configPath, 'utf-8');
+ const parsed = JSON.parse(content);
+ const rawServers = parsed.mcpServers;
+
+ if (!rawServers || typeof rawServers !== 'object') {
+ return null;
+ }
+
+ const servers: Record = {};
+
+ for (const [serverId, raw] of Object.entries(
+ rawServers as Record & { serverUrl?: string }>
+ )) {
+ if (raw.command) {
+ // stdio transport (standard format)
+ servers[serverId] = { ...raw, type: raw.type ?? 'stdio' } as McpServerConfig;
+ } else if (raw.serverUrl) {
+ // Antigravity-specific: 'serverUrl' → normalize to 'url'
+ const { serverUrl, ...rest } = raw;
+ servers[serverId] = { ...rest, url: serverUrl, type: 'http' } as McpServerConfig;
+ } else if (raw.url) {
+ // Standard url field
+ servers[serverId] = { ...raw, type: raw.type ?? 'http' } as McpServerConfig;
+ } else {
+ log(
+ 'WARN',
+ 'Invalid Antigravity MCP server configuration (no command, serverUrl, or url)',
+ {
+ serverId,
+ configPath,
+ }
+ );
+ }
+ }
+
+ if (Object.keys(servers).length === 0) {
+ return null;
+ }
+
+ log('INFO', 'Successfully read Antigravity mcp_config.json', {
+ configPath,
+ serverCount: Object.keys(servers).length,
+ });
+
+ return servers;
+ } catch (error) {
+ // File not found is expected
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
+ return null;
+ }
+
+ log('WARN', 'Failed to read Antigravity mcp_config.json', {
+ configPath,
+ error: error instanceof Error ? error.message : String(error),
+ });
+ return null;
+ }
+}
+
/**
* Read VSCode Copilot MCP config (.vscode/mcp.json)
*
@@ -704,10 +779,30 @@ export function getMcpServerConfig(
}
}
- // Server not found in any configuration (Claude, Copilot, Codex, Gemini, or Roo Code)
+ // =========================================================================
+ // Antigravity source (Priority 12)
+ // =========================================================================
+
+ // Priority 12: Antigravity user-scope (~/.gemini/antigravity/mcp_config.json)
+ const antigravityConfigPath = getAntigravityUserMcpConfigPath();
+ const antigravityConfig = readAntigravityMcpConfig(antigravityConfigPath);
+ if (antigravityConfig?.[serverId]) {
+ const serverConfig = normalizeServerConfig(antigravityConfig[serverId]);
+ if (serverConfig) {
+ log('INFO', 'Retrieved MCP server configuration from Antigravity', {
+ serverId,
+ scope: 'antigravity-user',
+ configPath: antigravityConfigPath,
+ type: serverConfig.type,
+ });
+ return { ...serverConfig, source: 'antigravity' };
+ }
+ }
+
+ // Server not found in any configuration
log(
'WARN',
- 'MCP server not found in any configuration (Claude, Copilot, Codex, Gemini, Roo Code)',
+ 'MCP server not found in any configuration (Claude, Copilot, Codex, Gemini, Roo Code, Antigravity)',
{
serverId,
workspacePath,
@@ -858,6 +953,18 @@ export function getAllMcpServerIds(workspacePath?: string): string[] {
}
}
+ // =========================================================================
+ // Antigravity source
+ // =========================================================================
+
+ // Collect from Antigravity user-scope (~/.gemini/antigravity/mcp_config.json)
+ const antigravityConfig = readAntigravityMcpConfig(getAntigravityUserMcpConfigPath());
+ if (antigravityConfig) {
+ for (const id of Object.keys(antigravityConfig)) {
+ serverIds.add(id);
+ }
+ }
+
return Array.from(serverIds);
} catch (error) {
log('ERROR', 'Failed to get MCP server list', {
@@ -890,6 +997,7 @@ export interface McpServerWithSource extends McpServerConfig {
* - Codex CLI (~/.codex/config.toml)
* - Gemini CLI (~/.gemini/settings.json, .gemini/settings.json)
* - Roo Code (.roo/mcp.json)
+ * - Antigravity (~/.gemini/antigravity/mcp_config.json)
*
* Priority order (first match wins for duplicate server IDs):
* 1. Project-scope Claude Code (/.mcp.json)
@@ -903,6 +1011,7 @@ export interface McpServerWithSource extends McpServerConfig {
* 9. User-scope Gemini CLI (~/.gemini/settings.json)
* 10. Project-scope Gemini CLI (/.gemini/settings.json)
* 11. Project-scope Roo Code (/.roo/mcp.json)
+ * 12. User-scope Antigravity (~/.gemini/antigravity/mcp_config.json)
*
* @param workspacePath - Optional workspace path for project-scoped servers
* @returns Array of MCP server configurations with source metadata
@@ -1033,6 +1142,11 @@ export function getAllMcpServersWithSource(workspacePath?: string): McpServerWit
addServers(rooProjectConfig, 'roo', rooProjectConfigPath);
}
+ // Priority 11: Antigravity user-scope (~/.gemini/antigravity/mcp_config.json)
+ const antigravityConfigPath = getAntigravityUserMcpConfigPath();
+ const antigravityConfig = readAntigravityMcpConfig(antigravityConfigPath);
+ addServers(antigravityConfig, 'antigravity', antigravityConfigPath);
+
log('INFO', 'Scanned all MCP server sources', {
totalServers: servers.length,
claudeCount: servers.filter((s) => s.source === 'claude').length,
@@ -1040,6 +1154,7 @@ export function getAllMcpServersWithSource(workspacePath?: string): McpServerWit
codexCount: servers.filter((s) => s.source === 'codex').length,
geminiCount: servers.filter((s) => s.source === 'gemini').length,
rooCount: servers.filter((s) => s.source === 'roo').length,
+ antigravityCount: servers.filter((s) => s.source === 'antigravity').length,
});
return servers;
diff --git a/src/extension/services/mcp-server-config-writer.ts b/src/extension/services/mcp-server-config-writer.ts
index 6cfb57aa..129c30ae 100644
--- a/src/extension/services/mcp-server-config-writer.ts
+++ b/src/extension/services/mcp-server-config-writer.ts
@@ -10,6 +10,7 @@
* - VSCode Copilot: {workspace}/.vscode/mcp.json
* - Copilot CLI: ~/.copilot/mcp-config.json (global)
* - Codex CLI: ~/.codex/config.toml (global)
+ * - Antigravity: ~/.gemini/antigravity/mcp_config.json (global)
*/
import * as fs from 'node:fs/promises';
@@ -49,6 +50,8 @@ function getConfigPath(target: McpConfigTarget, workspacePath: string): string {
return path.join(os.homedir(), '.codex', 'config.toml');
case 'gemini':
return path.join(os.homedir(), '.gemini', 'settings.json');
+ case 'antigravity':
+ return path.join(os.homedir(), '.gemini', 'antigravity', 'mcp_config.json');
}
}
@@ -121,6 +124,16 @@ export async function writeAgentConfig(
}
config.mcpServers[SERVER_ENTRY_NAME] = { url: serverUrl };
await writeJsonConfig(filePath, config);
+ } else if (target === 'antigravity') {
+ // Antigravity uses "mcpServers" key with { serverUrl: "..." } format
+ // in ~/.gemini/antigravity/mcp_config.json
+ const filePath = getConfigPath(target, workspacePath);
+ const config = await readJsonConfig(filePath);
+ if (!config.mcpServers) {
+ config.mcpServers = {};
+ }
+ config.mcpServers[SERVER_ENTRY_NAME] = { serverUrl };
+ await writeJsonConfig(filePath, config);
} else if (target === 'copilot-chat') {
// VSCode Copilot uses "servers" key with type "http"
const filePath = getConfigPath(target, workspacePath);
@@ -190,6 +203,14 @@ export async function removeAgentConfig(
delete config.mcpServers[SERVER_ENTRY_NAME];
await writeJsonConfig(filePath, config);
}
+ } else if (target === 'antigravity') {
+ // Antigravity uses "mcpServers" key
+ const filePath = getConfigPath(target, workspacePath);
+ const config = await readJsonConfig(filePath);
+ if (config.mcpServers?.[SERVER_ENTRY_NAME]) {
+ delete config.mcpServers[SERVER_ENTRY_NAME];
+ await writeJsonConfig(filePath, config);
+ }
} else if (target === 'copilot-chat') {
const filePath = getConfigPath(target, workspacePath);
const config = await readJsonConfig(filePath);
@@ -255,6 +276,8 @@ export function getConfigTargetsForProvider(provider: AiEditingProvider): McpCon
return ['roo-code'];
case 'gemini':
return ['gemini'];
+ case 'antigravity':
+ return ['antigravity'];
}
}
@@ -269,6 +292,7 @@ export async function removeAllAgentConfigs(workspacePath: string): Promise {
const skills: SkillReference[] = [];
@@ -397,6 +399,7 @@ export async function scanAllSkills(): Promise<{
const codexUserDir = getCodexUserSkillsDir();
const rooUserDir = getRooUserSkillsDir();
const geminiUserDir = getGeminiUserSkillsDir();
+ const antigravityUserDir = getAntigravityUserSkillsDir();
// Project directories
const claudeProjectDir = getProjectSkillsDir();
@@ -404,6 +407,7 @@ export async function scanAllSkills(): Promise<{
const codexProjectDir = getCodexProjectSkillsDir();
const rooProjectDir = getRooProjectSkillsDir();
const geminiProjectDir = getGeminiProjectSkillsDir();
+ const antigravityProjectDir = getAntigravityProjectSkillsDir();
const [
claudeUserSkills,
@@ -411,11 +415,13 @@ export async function scanAllSkills(): Promise<{
codexUserSkills,
rooUserSkills,
geminiUserSkills,
+ antigravityUserSkills,
claudeProjectSkills,
githubProjectSkills,
codexProjectSkills,
rooProjectSkills,
geminiProjectSkills,
+ antigravityProjectSkills,
pluginSkills,
] = await Promise.all([
// User-scope scans
@@ -424,12 +430,16 @@ export async function scanAllSkills(): Promise<{
scanSkills(codexUserDir, 'user', 'codex'),
scanSkills(rooUserDir, 'user', 'roo'),
scanSkills(geminiUserDir, 'user', 'gemini'),
+ scanSkills(antigravityUserDir, 'user', 'antigravity'),
// Project-scope scans
claudeProjectDir ? scanSkills(claudeProjectDir, 'project', 'claude') : Promise.resolve([]),
githubProjectDir ? scanSkills(githubProjectDir, 'project', 'copilot') : Promise.resolve([]),
codexProjectDir ? scanSkills(codexProjectDir, 'project', 'codex') : Promise.resolve([]),
rooProjectDir ? scanSkills(rooProjectDir, 'project', 'roo') : Promise.resolve([]),
geminiProjectDir ? scanSkills(geminiProjectDir, 'project', 'gemini') : Promise.resolve([]),
+ antigravityProjectDir
+ ? scanSkills(antigravityProjectDir, 'project', 'antigravity')
+ : Promise.resolve([]),
// Plugin skills
scanPluginSkills(),
]);
@@ -441,6 +451,7 @@ export async function scanAllSkills(): Promise<{
...codexUserSkills,
...rooUserSkills,
...geminiUserSkills,
+ ...antigravityUserSkills,
];
// Merge project skills: include all sources (no deduplication - show all available skills)
@@ -450,6 +461,7 @@ export async function scanAllSkills(): Promise<{
...codexProjectSkills,
...rooProjectSkills,
...geminiProjectSkills,
+ ...antigravityProjectSkills,
];
// Separate plugin skills by their scope
diff --git a/src/extension/services/workflow-prompt-generator.ts b/src/extension/services/workflow-prompt-generator.ts
index bd45b61a..e1dc8d95 100644
--- a/src/extension/services/workflow-prompt-generator.ts
+++ b/src/extension/services/workflow-prompt-generator.ts
@@ -404,7 +404,8 @@ export type ExportProvider =
| 'copilot-cli'
| 'codex'
| 'gemini'
- | 'roo-code';
+ | 'roo-code'
+ | 'antigravity';
/**
* Get the provider-specific sub-agent execution description for rectangle nodes.
@@ -423,6 +424,8 @@ function getSubAgentDescription(provider: ExportProvider): string {
return '- **Rectangle nodes (Sub-Agent: ...)**: Execute Sub-Agents';
case 'roo-code':
return '- **Rectangle nodes (Sub-Agent: ...)**: Execute Sub-Agents';
+ case 'antigravity':
+ return '- **Rectangle nodes (Sub-Agent: ...)**: Execute Sub-Agents';
default: {
const _exhaustiveCheck: never = provider;
throw new Error(`Unknown provider: ${_exhaustiveCheck}`);
@@ -447,6 +450,8 @@ function getAskUserQuestionDescription(provider: ExportProvider): string {
return '- **Diamond nodes (AskUserQuestion:...)**: Use the ask_user tool to prompt the user and branch based on their response';
case 'roo-code':
return '- **Diamond nodes (AskUserQuestion:...)**: Use the ask_followup_question tool to prompt the user and branch based on their response';
+ case 'antigravity':
+ return '- **Diamond nodes (AskUserQuestion:...)**: Prompt the user with a question and branch based on their response';
default: {
const _exhaustiveCheck: never = provider;
throw new Error(`Unknown provider: ${_exhaustiveCheck}`);
@@ -471,6 +476,8 @@ function getAgentName(provider: ExportProvider): string {
return 'Gemini CLI';
case 'roo-code':
return 'Roo Code';
+ case 'antigravity':
+ return 'Antigravity';
default: {
const _exhaustiveCheck: never = provider;
throw new Error(`Unknown provider: ${_exhaustiveCheck}`);
@@ -495,6 +502,8 @@ function getShellToolDescription(provider: ExportProvider): string {
return 'Use the run_shell_command tool to run';
case 'roo-code':
return 'Use the execute_command tool to run';
+ case 'antigravity':
+ return 'Use the Bash tool to run';
default: {
const _exhaustiveCheck: never = provider;
throw new Error(`Unknown provider: ${_exhaustiveCheck}`);
diff --git a/src/extension/utils/path-utils.ts b/src/extension/utils/path-utils.ts
index a412a67a..87563aa3 100644
--- a/src/extension/utils/path-utils.ts
+++ b/src/extension/utils/path-utils.ts
@@ -181,6 +181,36 @@ export function getGeminiProjectSkillsDir(): string | null {
return path.join(workspaceRoot, '.gemini', 'skills');
}
+/**
+ * Get the Antigravity (Google VSCode fork) user-scope Skills directory path
+ *
+ * @returns Absolute path to ~/.gemini/antigravity/skills/
+ *
+ * @example
+ * // Unix: /Users/username/.gemini/antigravity/skills
+ * // Windows: C:\Users\username\.gemini\antigravity\skills
+ */
+export function getAntigravityUserSkillsDir(): string {
+ return path.join(os.homedir(), '.gemini', 'antigravity', 'skills');
+}
+
+/**
+ * Get the Antigravity (Google VSCode fork) project-scope Skills directory path
+ *
+ * @returns Absolute path to .agent/skills/ in workspace root, or null if no workspace
+ *
+ * @example
+ * // Unix: /workspace/myproject/.agent/skills
+ * // Windows: C:\workspace\myproject\.agent\skills
+ */
+export function getAntigravityProjectSkillsDir(): string | null {
+ const workspaceRoot = getWorkspaceRoot();
+ if (!workspaceRoot) {
+ return null;
+ }
+ return path.join(workspaceRoot, '.agent', 'skills');
+}
+
// =====================================================================
// MCP Configuration Paths
// =====================================================================
@@ -261,6 +291,19 @@ export function getGeminiProjectMcpConfigPath(): string | null {
return path.join(workspaceRoot, '.gemini', 'settings.json');
}
+/**
+ * Get the Antigravity user-scope MCP config path (~/.gemini/antigravity/mcp_config.json)
+ *
+ * @returns Absolute path to ~/.gemini/antigravity/mcp_config.json
+ *
+ * @example
+ * // Unix: /Users/username/.gemini/antigravity/mcp_config.json
+ * // Windows: C:\Users\username\.gemini\antigravity\mcp_config.json
+ */
+export function getAntigravityUserMcpConfigPath(): string {
+ return path.join(os.homedir(), '.gemini', 'antigravity', 'mcp_config.json');
+}
+
/**
* Get the Roo Code project-scope MCP config path (.roo/mcp.json)
*
diff --git a/src/shared/types/mcp-node.ts b/src/shared/types/mcp-node.ts
index c4a699aa..4aa712dd 100644
--- a/src/shared/types/mcp-node.ts
+++ b/src/shared/types/mcp-node.ts
@@ -9,7 +9,7 @@
/**
* MCP configuration source provider
*/
-export type McpConfigSource = 'claude' | 'copilot' | 'codex' | 'gemini' | 'roo';
+export type McpConfigSource = 'claude' | 'copilot' | 'codex' | 'gemini' | 'roo' | 'antigravity';
/**
* MCP server reference information (from 'claude mcp list')
diff --git a/src/shared/types/messages.ts b/src/shared/types/messages.ts
index 6c80ee69..5a52b84d 100644
--- a/src/shared/types/messages.ts
+++ b/src/shared/types/messages.ts
@@ -189,9 +189,10 @@ export interface SkillReference {
* - 'codex': from ~/.codex/skills/ (user) or .codex/skills/ (project)
* - 'roo': from ~/.roo/skills/ (user) or .roo/skills/ (project)
* - 'gemini': from ~/.gemini/skills/ (user) or .gemini/skills/ (project)
+ * - 'antigravity': from ~/.agent/skills/ (user) or .agent/skills/ (project)
* - undefined: for local scope or legacy data
*/
- source?: 'claude' | 'copilot' | 'codex' | 'roo' | 'gemini';
+ source?: 'claude' | 'copilot' | 'codex' | 'roo' | 'gemini' | 'antigravity';
}
export interface CreateSkillPayload {
@@ -803,13 +804,20 @@ export type ExtensionMessage =
| Message
| Message
| Message
+ | Message
+ | Message
+ | Message
+ | Message
+ | Message
+ | Message
| Message
| Message
| Message
| Message
| Message
| Message
- | Message;
+ | Message
+ | Message;
// ============================================================================
// AI Slack Description Generation Payloads
@@ -1469,6 +1477,63 @@ export interface GeminiOperationFailedPayload {
timestamp: string; // ISO 8601
}
+// ============================================================================
+// Antigravity Integration Payloads (Beta)
+// ============================================================================
+
+/**
+ * Export workflow for Antigravity payload (Skills format)
+ * Exports to .claude/skills/{name}/SKILL.md
+ */
+export interface ExportForAntigravityPayload {
+ /** Workflow to export */
+ workflow: Workflow;
+}
+
+/**
+ * Export for Antigravity success payload
+ */
+export interface ExportForAntigravitySuccessPayload {
+ /** Skill name */
+ skillName: string;
+ /** Skill file path */
+ skillPath: string;
+ /** Timestamp */
+ timestamp: string; // ISO 8601
+}
+
+/**
+ * Run workflow for Antigravity payload
+ */
+export interface RunForAntigravityPayload {
+ /** Workflow to run */
+ workflow: Workflow;
+}
+
+/**
+ * Run for Antigravity success payload
+ */
+export interface RunForAntigravitySuccessPayload {
+ /** Workflow name */
+ workflowName: string;
+ /** Whether Antigravity Cascade was opened */
+ antigravityOpened: boolean;
+ /** Timestamp */
+ timestamp: string; // ISO 8601
+}
+
+/**
+ * Antigravity operation failed payload
+ */
+export interface AntigravityOperationFailedPayload {
+ /** Error code */
+ errorCode: 'ANTIGRAVITY_NOT_INSTALLED' | 'EXPORT_FAILED' | 'UNKNOWN_ERROR';
+ /** Error message */
+ errorMessage: string;
+ /** Timestamp */
+ timestamp: string; // ISO 8601
+}
+
// ============================================================================
// AI Editing Skill Payloads (MCP-based AI editing)
// ============================================================================
@@ -1482,7 +1547,8 @@ export type AiEditingProvider =
| 'copilot-chat'
| 'codex'
| 'roo-code'
- | 'gemini';
+ | 'gemini'
+ | 'antigravity';
/**
* Run AI editing skill request payload (Webview → Extension)
@@ -1554,7 +1620,8 @@ export type McpConfigTarget =
| 'copilot-chat'
| 'copilot-cli'
| 'codex'
- | 'gemini';
+ | 'gemini'
+ | 'antigravity';
/**
* Start MCP Server request payload (Webview → Extension)
@@ -1743,6 +1810,8 @@ export type WebviewMessage =
| Message
| Message
| Message
+ | Message
+ | Message
| Message
| Message
| Message
@@ -1750,7 +1819,9 @@ export type WebviewMessage =
| Message
| Message
| Message
- | Message;
+ | Message
+ | Message
+ | Message;
// ============================================================================
// Error Codes
diff --git a/src/webview/package-lock.json b/src/webview/package-lock.json
index 8ae46105..dccc0f68 100644
--- a/src/webview/package-lock.json
+++ b/src/webview/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cc-wf-studio-webview",
- "version": "3.24.1",
+ "version": "3.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cc-wf-studio-webview",
- "version": "3.24.1",
+ "version": "3.25.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@radix-ui/react-collapsible": "^1.1.12",
diff --git a/src/webview/package.json b/src/webview/package.json
index c36c70e3..50647558 100644
--- a/src/webview/package.json
+++ b/src/webview/package.json
@@ -1,6 +1,6 @@
{
"name": "cc-wf-studio-webview",
- "version": "3.24.1",
+ "version": "3.25.0",
"private": true,
"license": "AGPL-3.0-or-later",
"type": "module",
diff --git a/src/webview/src/components/Toolbar.tsx b/src/webview/src/components/Toolbar.tsx
index 9a35f3c5..f54d3183 100644
--- a/src/webview/src/components/Toolbar.tsx
+++ b/src/webview/src/components/Toolbar.tsx
@@ -16,12 +16,14 @@ import {
generateWorkflowName,
} from '../services/ai-generation-service';
import {
+ exportForAntigravity,
exportForCodexCli,
exportForCopilot,
exportForCopilotCli,
exportForGeminiCli,
exportForRooCode,
runAsSlashCommand,
+ runForAntigravity,
runForCodexCli,
runForCopilot,
runForCopilotCli,
@@ -104,6 +106,8 @@ export const Toolbar: React.FC = ({
toggleRooCodeEnabled,
isGeminiEnabled,
toggleGeminiEnabled,
+ isAntigravityEnabled,
+ toggleAntigravityEnabled,
} = useRefinementStore();
const [isSaving, setIsSaving] = useState(false);
const [isExporting, setIsExporting] = useState(false);
@@ -127,6 +131,9 @@ export const Toolbar: React.FC = ({
// Gemini CLI integration
const [isGeminiExporting, setIsGeminiExporting] = useState(false);
const [isGeminiRunning, setIsGeminiRunning] = useState(false);
+ // Antigravity integration
+ const [isAntigravityExporting, setIsAntigravityExporting] = useState(false);
+ const [isAntigravityRunning, setIsAntigravityRunning] = useState(false);
const generationNameRequestIdRef = useRef(null);
// Workflow name validation pattern (lowercase, numbers, hyphens, underscores only)
@@ -897,6 +904,104 @@ export const Toolbar: React.FC = ({
}
};
+ // ============================================================================
+ // Antigravity Integration Handlers
+ // ============================================================================
+
+ const handleAntigravityExport = async () => {
+ if (!workflowName.trim()) {
+ onError({
+ code: 'VALIDATION_ERROR',
+ message: t('toolbar.error.workflowNameRequiredForExport'),
+ });
+ return;
+ }
+
+ if (!WORKFLOW_NAME_PATTERN.test(workflowName)) {
+ onError({
+ code: 'VALIDATION_ERROR',
+ message: t('toolbar.error.workflowNameInvalid'),
+ });
+ return;
+ }
+
+ setIsAntigravityExporting(true);
+ try {
+ const { subAgentFlows, workflowDescription, slashCommandOptions } =
+ useWorkflowStore.getState();
+
+ const workflow = serializeWorkflow(
+ nodes,
+ edges,
+ workflowName,
+ workflowDescription || undefined,
+ undefined,
+ subAgentFlows,
+ slashCommandOptions
+ );
+
+ validateWorkflow(workflow);
+
+ const result = await exportForAntigravity(workflow);
+ console.log('Workflow exported as skill for Antigravity:', result.skillPath);
+ } catch (error) {
+ onError({
+ code: 'EXPORT_FAILED',
+ message: error instanceof Error ? error.message : 'Failed to export for Antigravity',
+ details: error,
+ });
+ } finally {
+ setIsAntigravityExporting(false);
+ }
+ };
+
+ const handleAntigravityRun = async () => {
+ if (!workflowName.trim()) {
+ onError({
+ code: 'VALIDATION_ERROR',
+ message: t('toolbar.error.workflowNameRequiredForExport'),
+ });
+ return;
+ }
+
+ if (!WORKFLOW_NAME_PATTERN.test(workflowName)) {
+ onError({
+ code: 'VALIDATION_ERROR',
+ message: t('toolbar.error.workflowNameInvalid'),
+ });
+ return;
+ }
+
+ setIsAntigravityRunning(true);
+ try {
+ const { subAgentFlows, workflowDescription, slashCommandOptions } =
+ useWorkflowStore.getState();
+
+ const workflow = serializeWorkflow(
+ nodes,
+ edges,
+ workflowName,
+ workflowDescription || undefined,
+ undefined,
+ subAgentFlows,
+ slashCommandOptions
+ );
+
+ validateWorkflow(workflow);
+
+ const result = await runForAntigravity(workflow);
+ console.log('Workflow run for Antigravity:', result.workflowName);
+ } catch (error) {
+ onError({
+ code: 'RUN_FAILED',
+ message: error instanceof Error ? error.message : 'Failed to run for Antigravity',
+ details: error,
+ });
+ } finally {
+ setIsAntigravityRunning(false);
+ }
+ };
+
// Handle AI workflow name generation
const handleGenerateWorkflowName = useCallback(async () => {
const currentRequestId = `gen-name-${Date.now()}`;
@@ -1151,7 +1256,8 @@ export const Toolbar: React.FC = ({
isCopilotCliEnabled ||
isCodexEnabled ||
isRooCodeEnabled ||
- isGeminiEnabled ? (
+ isGeminiEnabled ||
+ isAntigravityEnabled ? (
/* Combined layout when Copilot Beta is enabled */
= ({
)}
+
+ {/* Vertical Divider - shown when Antigravity is enabled */}
+ {isAntigravityEnabled && (
+
+ )}
+
+ {/* Antigravity Column - shown when Antigravity is enabled */}
+ {isAntigravityEnabled && (
+
+
+ Antigravity
+
+
+
+
+
+
+
+
+ )}
) : (
@@ -1921,6 +2119,8 @@ export const Toolbar: React.FC = ({
onToggleRooCodeBeta={toggleRooCodeEnabled}
isGeminiEnabled={isGeminiEnabled}
onToggleGeminiBeta={toggleGeminiEnabled}
+ isAntigravityEnabled={isAntigravityEnabled}
+ onToggleAntigravityBeta={toggleAntigravityEnabled}
open={moreActionsOpen}
onOpenChange={onMoreActionsOpenChange}
/>
diff --git a/src/webview/src/components/chat/McpServerSection.tsx b/src/webview/src/components/chat/McpServerSection.tsx
index f419eff3..5af0ae51 100644
--- a/src/webview/src/components/chat/McpServerSection.tsx
+++ b/src/webview/src/components/chat/McpServerSection.tsx
@@ -18,6 +18,7 @@ import { useTranslation } from '../../i18n/i18n-context';
import { vscode } from '../../main';
import { launchAiAgent, openExternalUrl } from '../../services/vscode-bridge';
import { useRefinementStore } from '../../stores/refinement-store';
+import { AntigravityMcpRefreshDialog } from '../dialogs/AntigravityMcpRefreshDialog';
interface AiEditButton {
provider: AiEditingProvider;
@@ -31,6 +32,7 @@ const AI_EDIT_BUTTONS: AiEditButton[] = [
{ provider: 'codex', label: 'Codex CLI' },
{ provider: 'roo-code', label: 'Roo Code' },
{ provider: 'gemini', label: 'Gemini CLI' },
+ { provider: 'antigravity', label: 'Antigravity' },
];
interface McpServerSectionProps {
@@ -44,6 +46,7 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
const [port, setPort] = useState(null);
const [launchingProvider, setLaunchingProvider] = useState(null);
const [reviewBeforeApply, setReviewBeforeApply] = useState(true);
+ const [showMcpRefreshDialog, setShowMcpRefreshDialog] = useState(false);
const {
isCopilotChatEnabled,
@@ -51,6 +54,7 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
isCodexEnabled,
isRooCodeEnabled,
isGeminiEnabled,
+ isAntigravityEnabled,
} = useRefinementStore();
const visibleButtons = useMemo(() => {
@@ -68,6 +72,8 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
return isRooCodeEnabled;
case 'gemini':
return isGeminiEnabled;
+ case 'antigravity':
+ return isAntigravityEnabled;
default:
return false;
}
@@ -78,6 +84,7 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
isCodexEnabled,
isRooCodeEnabled,
isGeminiEnabled,
+ isAntigravityEnabled,
]);
// Listen for MCP server status updates
@@ -90,6 +97,10 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
setPort(payload.port);
setReviewBeforeApply(payload.reviewBeforeApply);
}
+ if (message.type === 'ANTIGRAVITY_MCP_REFRESH_NEEDED') {
+ setLaunchingProvider(null);
+ setShowMcpRefreshDialog(true);
+ }
};
window.addEventListener('message', handler);
@@ -115,6 +126,19 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
[launchingProvider]
);
+ const handleMcpRefreshOpenSettings = useCallback(() => {
+ vscode.postMessage({ type: 'OPEN_ANTIGRAVITY_MCP_SETTINGS' });
+ }, []);
+
+ const handleMcpRefreshRun = useCallback(() => {
+ setShowMcpRefreshDialog(false);
+ vscode.postMessage({ type: 'CONFIRM_ANTIGRAVITY_CASCADE_LAUNCH' });
+ }, []);
+
+ const handleMcpRefreshCancel = useCallback(() => {
+ setShowMcpRefreshDialog(false);
+ }, []);
+
const handleStop = useCallback(() => {
vscode.postMessage({ type: 'STOP_MCP_SERVER' });
}, []);
@@ -135,6 +159,14 @@ export function McpServerSection({ isCollapsed, onToggleCollapse }: McpServerSec
overflow: 'hidden',
}}
>
+ {/* Antigravity MCP Refresh Dialog */}
+
+
{/* Header */}