-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat: add Antigravity profile with MCP auto-configuration #1682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
8bc597c
ea20d79
aa755d6
a343e81
56babd8
f908c0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "task-master-ai": minor | ||
| --- | ||
|
|
||
| Add Antigravity as a selectable initialization profile in `task-master init` that creates MCP configuration in the project root directory as `.gemini/antigravity/mcp_config.json` with task-master-ai server settings. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,46 @@ | ||
| { | ||
| "models": { | ||
| "main": { | ||
| "provider": "claude-code", | ||
| "modelId": "opus", | ||
| "maxTokens": 32000, | ||
| "temperature": 0.2 | ||
| }, | ||
| "research": { | ||
| "provider": "perplexity", | ||
| "modelId": "sonar-reasoning-pro", | ||
| "maxTokens": 8700, | ||
| "temperature": 0.1 | ||
| }, | ||
| "fallback": { | ||
| "provider": "claude-code", | ||
| "modelId": "sonnet", | ||
| "maxTokens": 64000, | ||
| "temperature": 0.2 | ||
| } | ||
| }, | ||
| "global": { | ||
| "logLevel": "silent", | ||
| "debug": false, | ||
| "defaultNumTasks": 10, | ||
| "defaultSubtasks": 5, | ||
| "defaultPriority": "medium", | ||
| "projectName": "Taskmaster", | ||
| "ollamaBaseURL": "http://localhost:11434/api", | ||
| "bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com", | ||
| "responseLanguage": "English", | ||
| "enableCodebaseAnalysis": true, | ||
| "enableProxy": false, | ||
| "anonymousTelemetry": true, | ||
| "userId": "1234567890", | ||
| "azureBaseURL": "https://your-endpoint.azure.com/", | ||
| "defaultTag": "master" | ||
| }, | ||
| "claudeCode": {}, | ||
| "codexCli": {}, | ||
| "grokCli": { | ||
| "timeout": 120000, | ||
| "workingDirectory": null, | ||
| "defaultModel": "grok-4-latest" | ||
| } | ||
| } | ||
| "models": { | ||
| "main": { | ||
| "provider": "claude-code", | ||
| "modelId": "opus", | ||
| "maxTokens": 32000, | ||
| "temperature": 0.2 | ||
| }, | ||
| "research": { | ||
| "provider": "perplexity", | ||
| "modelId": "sonar-reasoning-pro", | ||
| "maxTokens": 8700, | ||
| "temperature": 0.1 | ||
| }, | ||
| "fallback": { | ||
| "provider": "claude-code", | ||
| "modelId": "sonnet", | ||
| "maxTokens": 64000, | ||
| "temperature": 0.2 | ||
| } | ||
| }, | ||
| "global": { | ||
| "logLevel": "silent", | ||
| "debug": false, | ||
| "defaultNumTasks": 10, | ||
| "defaultSubtasks": 5, | ||
| "defaultPriority": "medium", | ||
| "projectName": "Taskmaster", | ||
| "ollamaBaseURL": "http://localhost:11434/api", | ||
| "bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com", | ||
| "responseLanguage": "English", | ||
| "enableCodebaseAnalysis": true, | ||
| "enableProxy": false, | ||
| "anonymousTelemetry": true, | ||
| "userId": "1234567890", | ||
| "azureBaseURL": "https://your-endpoint.azure.com/", | ||
| "defaultTag": "master" | ||
| }, | ||
| "claudeCode": {}, | ||
| "codexCli": {}, | ||
| "grokCli": { | ||
| "timeout": 120000, | ||
| "workingDirectory": null, | ||
| "defaultModel": "grok-4-latest" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,141 @@ | ||||||||||||||||
| import fs from 'fs'; | ||||||||||||||||
| import path from 'path'; | ||||||||||||||||
| import { log } from '../../scripts/modules/utils.js'; | ||||||||||||||||
| import { createProfile } from './base-profile.js'; | ||||||||||||||||
|
|
||||||||||||||||
| function isInstalled(targetDir) { | ||||||||||||||||
| // Check if Antigravity MCP config exists and contains task-master-ai server | ||||||||||||||||
| const mcpConfigPath = path.join(targetDir, '.gemini', 'antigravity', 'mcp_config.json'); | ||||||||||||||||
|
|
||||||||||||||||
| try { | ||||||||||||||||
| if (!fs.existsSync(mcpConfigPath)) { | ||||||||||||||||
| return false; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| const config = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8')); | ||||||||||||||||
| return config.mcpServers && config.mcpServers['task-master-ai']; | ||||||||||||||||
|
Comment on lines
+16
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion | π Major Use shared The current direct As per coding guidelines: "Use readJSON and writeJSON utilities for all JSON file operations instead of raw fs.readFileSync or fs.writeFileSync." Also applies to: 40-40, 60-60, 76-76, 92-92, 102-102 π€ Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On Line 16, the function currently returns the server object or Suggested fix- return config.mcpServers && config.mcpServers['task-master-ai'];
+ return Boolean(config?.mcpServers?.['task-master-ai']);π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||
| } catch (error) { | ||||||||||||||||
| log('debug', `[Antigravity] Error checking installation: ${error.message}`); | ||||||||||||||||
| return false; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| function onAddRulesProfile(targetDir, assetsDir) { | ||||||||||||||||
| // Antigravity creates MCP config in project root .gemini/antigravity/ directory | ||||||||||||||||
| const geminiDir = path.join(targetDir, '.gemini'); | ||||||||||||||||
| const antigravityDir = path.join(geminiDir, 'antigravity'); | ||||||||||||||||
| const mcpConfigPath = path.join(antigravityDir, 'mcp_config.json'); | ||||||||||||||||
|
|
||||||||||||||||
| try { | ||||||||||||||||
| // Ensure directories exist | ||||||||||||||||
| if (!fs.existsSync(geminiDir)) { | ||||||||||||||||
| fs.mkdirSync(geminiDir, { recursive: true }); | ||||||||||||||||
| } | ||||||||||||||||
| if (!fs.existsSync(antigravityDir)) { | ||||||||||||||||
| fs.mkdirSync(antigravityDir, { recursive: true }); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Check if config already exists | ||||||||||||||||
| if (fs.existsSync(mcpConfigPath)) { | ||||||||||||||||
| const existingConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8')); | ||||||||||||||||
|
|
||||||||||||||||
| // Check if task-master-ai server is already configured | ||||||||||||||||
| if (existingConfig.mcpServers && existingConfig.mcpServers['task-master-ai']) { | ||||||||||||||||
| log('info', `[Antigravity] Task Master AI server already configured in MCP config`); | ||||||||||||||||
| return; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Add task-master-ai server to existing config | ||||||||||||||||
| if (!existingConfig.mcpServers) { | ||||||||||||||||
| existingConfig.mcpServers = {}; | ||||||||||||||||
| } | ||||||||||||||||
| existingConfig.mcpServers['task-master-ai'] = { | ||||||||||||||||
| command: 'npx', | ||||||||||||||||
| args: ['-y', 'task-master-ai', 'mcp-server'], | ||||||||||||||||
| env: { | ||||||||||||||||
| TASK_MASTER_PROJECT_ROOT: targetDir | ||||||||||||||||
| } | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| fs.writeFileSync(mcpConfigPath, JSON.stringify(existingConfig, null, 2) + '\n'); | ||||||||||||||||
| log('info', `[Antigravity] Added Task Master AI server to existing MCP config`); | ||||||||||||||||
| } else { | ||||||||||||||||
| // Create new MCP config | ||||||||||||||||
| const mcpConfig = { | ||||||||||||||||
| mcpServers: { | ||||||||||||||||
| 'task-master-ai': { | ||||||||||||||||
| command: 'npx', | ||||||||||||||||
| args: ['-y', 'task-master-ai', 'mcp-server'], | ||||||||||||||||
| env: { | ||||||||||||||||
| TASK_MASTER_PROJECT_ROOT: targetDir | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n'); | ||||||||||||||||
| log('info', `[Antigravity] Created MCP config at ${mcpConfigPath}`); | ||||||||||||||||
| } | ||||||||||||||||
| } catch (error) { | ||||||||||||||||
| log('error', `[Antigravity] Failed to create MCP config: ${error.message}`); | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+80
to
+82
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not swallow setup failures in Catching and only logging here can report a successful profile add even when MCP config creation failed. Suggested fix } catch (error) {
log('error', `[Antigravity] Failed to create MCP config: ${error.message}`);
+ throw error;
}π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| function onRemoveRulesProfile(targetDir) { | ||||||||||||||||
| // Clean up Antigravity MCP config from project .gemini/antigravity/ | ||||||||||||||||
| const antigravityDir = path.join(targetDir, '.gemini', 'antigravity'); | ||||||||||||||||
| const mcpConfigPath = path.join(antigravityDir, 'mcp_config.json'); | ||||||||||||||||
|
|
||||||||||||||||
| try { | ||||||||||||||||
| if (fs.existsSync(mcpConfigPath)) { | ||||||||||||||||
| // Read current config and remove task-master-ai server | ||||||||||||||||
| const config = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8')); | ||||||||||||||||
| if (config.mcpServers && config.mcpServers['task-master-ai']) { | ||||||||||||||||
| delete config.mcpServers['task-master-ai']; | ||||||||||||||||
|
|
||||||||||||||||
| // If no servers left, remove the file | ||||||||||||||||
| if (Object.keys(config.mcpServers).length === 0) { | ||||||||||||||||
| fs.rmSync(mcpConfigPath, { force: true }); | ||||||||||||||||
| log('info', `[Antigravity] Removed empty MCP config file`); | ||||||||||||||||
|
Comment on lines
+98
to
+100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid deleting the whole config file when non-server keys may still exist. If Suggested fix- // If no servers left, remove the file
- if (Object.keys(config.mcpServers).length === 0) {
- fs.rmSync(mcpConfigPath, { force: true });
- log('info', `[Antigravity] Removed empty MCP config file`);
+ // If no servers left, only remove file when config is otherwise empty
+ if (Object.keys(config.mcpServers).length === 0) {
+ delete config.mcpServers;
+ if (Object.keys(config).length === 0) {
+ fs.rmSync(mcpConfigPath, { force: true });
+ log('info', `[Antigravity] Removed empty MCP config file`);
+ } else {
+ fs.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n');
+ log('info', `[Antigravity] Removed Task Master from MCP config`);
+ }
} else {π€ Prompt for AI Agents |
||||||||||||||||
| } else { | ||||||||||||||||
| // Update config with task-master-ai removed | ||||||||||||||||
| fs.writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2) + '\n'); | ||||||||||||||||
| log('info', `[Antigravity] Removed Task Master from MCP config`); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // Clean up empty directories | ||||||||||||||||
| try { | ||||||||||||||||
| if (fs.existsSync(antigravityDir) && fs.readdirSync(antigravityDir).length === 0) { | ||||||||||||||||
| fs.rmSync(antigravityDir, { recursive: true, force: true }); | ||||||||||||||||
| log('debug', `[Antigravity] Removed empty antigravity directory`); | ||||||||||||||||
| } | ||||||||||||||||
| const geminiDir = path.join(targetDir, '.gemini'); | ||||||||||||||||
| if (fs.existsSync(geminiDir) && fs.readdirSync(geminiDir).length === 0) { | ||||||||||||||||
| fs.rmSync(geminiDir, { recursive: true, force: true }); | ||||||||||||||||
| log('debug', `[Antigravity] Removed empty .gemini directory`); | ||||||||||||||||
| } | ||||||||||||||||
| } catch (dirError) { | ||||||||||||||||
| // Directory cleanup is not critical | ||||||||||||||||
| } | ||||||||||||||||
| } catch (error) { | ||||||||||||||||
| log('error', `[Antigravity] Failed to clean up MCP config: ${error.message}`); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| export const antigravityProfile = createProfile({ | ||||||||||||||||
| name: 'antigravity', | ||||||||||||||||
| displayName: 'Antigravity', | ||||||||||||||||
| url: 'https://antigravity.dev', | ||||||||||||||||
| docsUrl: 'https://antigravity.dev/docs', | ||||||||||||||||
| profileDir: '.gemini/antigravity', | ||||||||||||||||
| rulesDir: '.', | ||||||||||||||||
| mcpConfig: true, | ||||||||||||||||
| mcpConfigName: 'mcp_config.json', | ||||||||||||||||
| includeDefaultRules: false, | ||||||||||||||||
| fileMap: {}, | ||||||||||||||||
| isInstalled, | ||||||||||||||||
| onAdd: onAddRulesProfile, | ||||||||||||||||
| onRemove: onRemoveRulesProfile | ||||||||||||||||
| }); | ||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,12 @@ | ||||||
| import { RULE_PROFILES } from '../../src/constants/profiles.js'; | ||||||
| import { getRulesProfile } from '../../src/utils/rule-transformer.js'; | ||||||
|
|
||||||
| describe('Antigravity profile', () => { | ||||||
| it('is registered and resolves correctly', () => { | ||||||
| expect(RULE_PROFILES).toContain('antigravity'); | ||||||
| const profile = getRulesProfile('antigravity'); | ||||||
| expect(profile).toBeDefined(); | ||||||
| expect(profile.displayName).toBe('Antigravity'); | ||||||
| expect(profile.mcpConfig).toBe(false); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On Line 10, Suggested fix- expect(profile.mcpConfig).toBe(false);
+ expect(profile.mcpConfig).toBe(true);π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||
| }); | ||||||
| }); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid manual edits to
.taskmaster/config.json.This looks like formatting-only churn in a managed file; please update this via the supported command flow instead of direct edits.
As per coding guidelines: "Do not manually edit .taskmaster/config.json; use task-master models command or models MCP tool to manage configuration."
π€ Prompt for AI Agents