Files
gravity_control/extension/out/extension.js

367 lines
14 KiB
JavaScript

"use strict";
/**
* Gravity Bridge — VS Code Extension (SDK Edition)
*
* Uses antigravity-sdk for:
* - Real-time step/conversation monitoring via EventMonitor
* - Full conversation content via LSBridge.getConversation()
* - Message sending via CascadeManager.sendPrompt()
* - Accept/Reject via CascadeManager.acceptStep()/rejectStep()
*
* Communication with Discord via file-based bridge protocol.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const cp = __importStar(require("child_process"));
// antigravity-sdk embedded locally (src/sdk/)
let AntigravitySDK;
let sdk;
let statusBar;
let bridgePath;
let projectName;
let isActive = false;
let watcher = null;
let commandsWatcher = null;
const sentPendingIds = new Set();
// ─── Project Detection ───
function detectProjectName() {
const config = vscode.workspace.getConfiguration('gravityBridge');
const configName = config.get('projectName');
if (configName) {
return configName;
}
const folders = vscode.workspace.workspaceFolders;
if (folders && folders.length > 0) {
const cwd = folders[0].uri.fsPath;
try {
const remoteUrl = cp.execSync('git remote get-url origin', {
cwd, encoding: 'utf-8', timeout: 3000
}).trim();
const match = remoteUrl.match(/\/([^\/]+?)(?:\.git)?$/);
if (match && match[1]) {
return match[1].toLowerCase().replace(/[\s\-]+/g, '_');
}
}
catch { }
return path.basename(cwd).toLowerCase().replace(/[\s\-]+/g, '_');
}
return 'default';
}
// ─── Bridge File I/O ───
function ensureBridgeDir() {
const dirs = ['', 'response', 'commands'];
for (const d of dirs) {
const p = path.join(bridgePath, d);
if (!fs.existsSync(p)) {
fs.mkdirSync(p, { recursive: true });
}
}
}
function writeChatSnapshot(text) {
try {
const filePath = path.join(bridgePath, 'response', 'chat_snapshot.txt');
fs.writeFileSync(filePath, text, 'utf-8');
console.log(`Gravity Bridge: chat snapshot written (${text.length} chars)`);
}
catch (e) {
console.log(`Gravity Bridge: snapshot write error: ${e.message}`);
}
}
function writePendingApproval(data) {
try {
const filePath = path.join(bridgePath, 'response', 'pending_approval.json');
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
}
catch { }
}
// ─── Command File Watcher (Discord → Antigravity) ───
function processCommandFile(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
const cmd = JSON.parse(content);
// Ignore commands for other projects
if (cmd.project_name && cmd.project_name !== projectName) {
console.log(`Gravity Bridge: skipping command for "${cmd.project_name}"`);
return;
}
console.log(`Gravity Bridge: command — "${cmd.message || cmd.action}"`);
if (cmd.action === 'approve' && sdk) {
sdk.cascade.acceptStep().catch((e) => console.log(`Gravity Bridge: approve error: ${e.message}`));
}
else if (cmd.action === 'reject' && sdk) {
sdk.cascade.rejectStep().catch((e) => console.log(`Gravity Bridge: reject error: ${e.message}`));
}
else if (cmd.action === 'approve_terminal' && sdk) {
sdk.cascade.acceptTerminalCommand().catch((e) => console.log(`Gravity Bridge: approve_terminal error: ${e.message}`));
}
else if (cmd.message && sdk) {
// Send message to Antigravity
sdk.cascade.sendPrompt(cmd.message).then(() => {
console.log(`Gravity Bridge: ✅ sent via SDK sendPrompt`);
}).catch((e) => {
// Fallback to VS Code command
console.log(`Gravity Bridge: SDK sendPrompt failed: ${e.message}, trying command...`);
vscode.commands.executeCommand('antigravity.sendPromptToAgentPanel', cmd.message)
.then(() => console.log('Gravity Bridge: ✅ sent via sendPromptToAgentPanel'));
});
}
// Remove processed command file
try {
fs.unlinkSync(filePath);
}
catch { }
}
catch (e) {
console.log(`Gravity Bridge: command processing error: ${e.message}`);
}
}
function watchCommandsDir() {
const cmdDir = path.join(bridgePath, 'commands');
// Process existing files
try {
for (const f of fs.readdirSync(cmdDir)) {
if (f.endsWith('.json')) {
processCommandFile(path.join(cmdDir, f));
}
}
}
catch { }
// Watch for new files
try {
commandsWatcher = fs.watch(cmdDir, (event, filename) => {
if (filename && filename.endsWith('.json') && event === 'rename') {
const fp = path.join(cmdDir, filename);
if (fs.existsSync(fp)) {
setTimeout(() => processCommandFile(fp), 200);
}
}
});
}
catch { }
}
// ─── SDK Integration ───
async function initSDK(context) {
try {
const sdkModule = require('./sdk/index');
AntigravitySDK = sdkModule.AntigravitySDK;
}
catch (err) {
console.log(`Gravity Bridge: antigravity-sdk load failed: ${err.message}`);
return false;
}
try {
sdk = new AntigravitySDK(context);
await sdk.initialize();
console.log('Gravity Bridge: ✅ SDK initialized');
return true;
}
catch (err) {
console.log(`Gravity Bridge: SDK init failed: ${err.message}`);
return false;
}
}
function setupMonitor() {
if (!sdk) {
return;
}
// Step count changed → fetch conversation content
sdk.monitor.onStepCountChanged(async (e) => {
console.log(`Gravity Bridge: [SDK] step changed: "${e.title}" step ${e.newCount} (+${e.delta})`);
// Get fresh session to have the ID
try {
const conversation = await sdk.ls.getConversation(e.sessionId);
if (conversation && conversation.messages) {
// Find the last assistant message
const assistantMsgs = conversation.messages.filter((m) => m.role === 'assistant' && m.content);
if (assistantMsgs.length > 0) {
const lastMsg = assistantMsgs[assistantMsgs.length - 1];
const text = `🤖 **${e.title}**\n\n${lastMsg.content}`;
writeChatSnapshot(text);
console.log(`Gravity Bridge: [SDK] relayed AI response (${lastMsg.content.length} chars)`);
return;
}
}
// Find PlannerResponse steps
if (conversation && conversation.steps) {
const responses = conversation.steps.filter((s) => s.type === 'PlannerResponse' && s.summary);
if (responses.length > 0) {
const last = responses[responses.length - 1];
writeChatSnapshot(`🤖 **${e.title}**\n\n${last.summary}`);
console.log(`Gravity Bridge: [SDK] relayed PlannerResponse (${last.summary.length} chars)`);
return;
}
}
}
catch (err) {
console.log(`Gravity Bridge: [SDK] getConversation error: ${err.message}`);
}
// Fallback: just send the title + step info
writeChatSnapshot(`🤖 **${e.title}**\n\n(step ${e.newCount}, +${e.delta})`);
});
// New conversation started
sdk.monitor.onNewConversation(() => {
console.log('Gravity Bridge: [SDK] new conversation detected');
});
// Active session changed
sdk.monitor.onActiveSessionChanged((e) => {
console.log(`Gravity Bridge: [SDK] active session: "${e.title}" (${e.sessionId?.substring(0, 8)})`);
});
// State changed (USS update)
sdk.monitor.onStateChanged((e) => {
console.log(`Gravity Bridge: [SDK] state changed: ${e.key}`);
});
// Start monitoring (USS every 3s, trajectory every 2s for faster detection)
sdk.monitor.start(3000, 2000);
console.log('Gravity Bridge: [SDK] monitor started (USS 3s, trajectory 2s)');
}
// ─── Activation ───
async function activate(context) {
console.log('Gravity Bridge: activating...');
// Project detection
projectName = detectProjectName();
console.log(`Gravity Bridge: project "${projectName}"`);
// Bridge path
const config = vscode.workspace.getConfiguration('gravityBridge');
const configPath = config.get('bridgePath');
bridgePath = configPath || path.join(os.homedir(), '.gemini', 'antigravity', 'bridge');
ensureBridgeDir();
console.log(`Gravity Bridge: bridge path: ${bridgePath}`);
// Status bar
statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
statusBar.text = '$(sync~spin) Bridge';
statusBar.tooltip = `Gravity Bridge: ${projectName}`;
statusBar.show();
context.subscriptions.push(statusBar);
// Initialize SDK
const sdkReady = await initSDK(context);
if (sdkReady) {
setupMonitor();
statusBar.text = '$(check) Bridge SDK';
statusBar.tooltip = `Gravity Bridge: ${projectName} (SDK active)`;
// Register SDK-powered commands
context.subscriptions.push(vscode.commands.registerCommand('gravityBridge.approve', async () => {
try {
await sdk.cascade.acceptStep();
vscode.window.showInformationMessage('Gravity Bridge: Step approved');
}
catch (e) {
vscode.window.showErrorMessage(`Approve failed: ${e.message}`);
}
}), vscode.commands.registerCommand('gravityBridge.reject', async () => {
try {
await sdk.cascade.rejectStep();
vscode.window.showInformationMessage('Gravity Bridge: Step rejected');
}
catch (e) {
vscode.window.showErrorMessage(`Reject failed: ${e.message}`);
}
}));
}
else {
statusBar.text = '$(warning) Bridge (no SDK)';
console.log('Gravity Bridge: SDK not available, file-based mode only');
}
// Watch commands directory
watchCommandsDir();
// Register basic commands
context.subscriptions.push(vscode.commands.registerCommand('gravityBridge.start', () => {
isActive = true;
statusBar.text = sdkReady ? '$(check) Bridge SDK' : '$(sync~spin) Bridge';
vscode.window.showInformationMessage(`Gravity Bridge started for "${projectName}"`);
}), vscode.commands.registerCommand('gravityBridge.stop', () => {
isActive = false;
if (sdk) {
sdk.monitor.stop();
}
statusBar.text = '$(circle-slash) Bridge OFF';
vscode.window.showInformationMessage('Gravity Bridge stopped');
}), vscode.commands.registerCommand('gravityBridge.connect', async () => {
if (!sdk) {
vscode.window.showErrorMessage('SDK not initialized');
return;
}
try {
const sessions = await sdk.cascade.getSessions();
const items = sessions.map((s) => ({
label: s.title || 'Untitled',
description: `step ${s.stepCount}${s.id?.substring(0, 8)}`,
sessionId: s.id,
}));
const pick = await vscode.window.showQuickPick(items, {
placeHolder: 'Select a conversation to connect'
});
if (pick) {
await sdk.cascade.focusSession(pick.sessionId);
vscode.window.showInformationMessage(`Connected to: ${pick.label}`);
}
}
catch (e) {
vscode.window.showErrorMessage(`Connect failed: ${e.message}`);
}
}));
// Cleanup
context.subscriptions.push({
dispose: () => {
if (sdk) {
sdk.monitor.stop();
sdk.dispose();
}
if (watcher) {
watcher.close();
}
if (commandsWatcher) {
commandsWatcher.close();
}
}
});
console.log('Gravity Bridge: ✅ activated');
isActive = true;
}
function deactivate() {
if (sdk) {
try {
sdk.monitor.stop();
sdk.dispose();
}
catch { }
}
}
//# sourceMappingURL=extension.js.map