diff --git a/extension/gravity-bridge-0.2.0.vsix b/extension/gravity-bridge-0.2.0.vsix index b4265f7..91ddf87 100644 Binary files a/extension/gravity-bridge-0.2.0.vsix and b/extension/gravity-bridge-0.2.0.vsix differ diff --git a/extension/out/extension.js b/extension/out/extension.js index b161518..61ad518 100644 --- a/extension/out/extension.js +++ b/extension/out/extension.js @@ -1,13 +1,14 @@ "use strict"; /** - * Gravity Bridge — VS Code Extension + * Gravity Bridge — VS Code Extension (SDK Edition) * - * Bridges Antigravity IDE approval dialogs to the Discord bot via file-based protocol. + * 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() * - * Multi-project routing: - * - Each workspace has a project name (from settings or workspace folder name) - * - Extension only processes commands/responses matching its project_name - * - Pending approvals include project_name for Discord channel routing + * 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; @@ -44,32 +45,29 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.activate = activate; -exports.writePendingApproval = writePendingApproval; exports.deactivate = deactivate; const vscode = __importStar(require("vscode")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); -let watcher = null; -let commandsWatcher = null; +const cp = __importStar(require("child_process")); +// antigravity-sdk is loaded at runtime +let AntigravitySDK; +let sdk; let statusBar; let bridgePath; let projectName; let isActive = false; -// Track pending approvals we've already sent +let watcher = null; +let commandsWatcher = null; const sentPendingIds = new Set(); -const cp = __importStar(require("child_process")); -/** - * Detect project name from workspace. - * Priority: settings > git remote repo name > workspace folder name - */ +// ─── Project Detection ─── function detectProjectName() { const config = vscode.workspace.getConfiguration('gravityBridge'); const configName = config.get('projectName'); if (configName) { return configName; } - // Try git remote URL → extract repo name const folders = vscode.workspace.workspaceFolders; if (folders && folders.length > 0) { const cwd = folders[0].uri.fsPath; @@ -77,1039 +75,293 @@ function detectProjectName() { const remoteUrl = cp.execSync('git remote get-url origin', { cwd, encoding: 'utf-8', timeout: 3000 }).trim(); - // "https://gitea.example.com/Variet/gravity_control.git" → "gravity_control" - // "git@github.com:user/repo.git" → "repo" const match = remoteUrl.match(/\/([^\/]+?)(?:\.git)?$/); if (match && match[1]) { - const repoName = match[1].toLowerCase().replace(/[\s\-]+/g, '_'); - console.log(`Gravity Bridge: project from git remote → "${repoName}"`); - return repoName; + return match[1].toLowerCase().replace(/[\s\-]+/g, '_'); } } - catch { - // No git or no remote — fall through - } - // Fallback: workspace folder name - return folders[0].name.toLowerCase().replace(/[\s\-]+/g, '_'); + catch { } + return path.basename(cwd).toLowerCase().replace(/[\s\-]+/g, '_'); } - return 'unknown_project'; + return 'default'; } -function activate(context) { - projectName = detectProjectName(); - console.log(`Gravity Bridge: activating for project "${projectName}"...`); - // Determine bridge path - const config = vscode.workspace.getConfiguration('gravityBridge'); - const configPath = config.get('bridgePath'); - bridgePath = configPath || path.join(os.homedir(), '.gemini', 'antigravity', 'bridge'); - // Ensure bridge directories exist - const dirs = ['pending', 'response', 'commands', 'register']; - for (const dir of dirs) { - const dirPath = path.join(bridgePath, dir); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { recursive: true }); +// ─── 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 }); } } - // Status bar - statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); - statusBar.command = 'gravityBridge.start'; - statusBar.text = `$(radio-tower) ${projectName}: Off`; - statusBar.tooltip = `Gravity Bridge — ${projectName}`; - statusBar.show(); - context.subscriptions.push(statusBar); - // Register commands - context.subscriptions.push(vscode.commands.registerCommand('gravityBridge.start', startBridge), vscode.commands.registerCommand('gravityBridge.stop', stopBridge), vscode.commands.registerCommand('gravityBridge.connect', connectSession), vscode.commands.registerCommand('gravityBridge.approve', () => handleManualAction(true)), vscode.commands.registerCommand('gravityBridge.reject', () => handleManualAction(false))); - // === LS ConnectRPC Bridge: Relay AI responses to Discord === - let lsPort = null; - let lsCsrf = ''; - let lsPid = null; - let lsUseTls = false; // track detected protocol - let lastStepIndex = {}; // cascadeId → last known step index - async function discoverLS() { - return new Promise((resolve) => { - // Phase 1: Find LS process → PID + CSRF token - cp.exec('powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object {$_.Name -eq \'language_server_exe.exe\' -or ($_.CommandLine -and $_.CommandLine -like \'*language_server*\' -and $_.CommandLine -notlike \'*powershell*\')} | Select-Object ProcessId, CommandLine | ConvertTo-Json"', { maxBuffer: 2 * 1024 * 1024 }, (err, stdout) => { - if (err || !stdout.trim()) { - console.log(`Gravity Bridge: [LS] process not found`); - resolve(false); - return; - } - try { - let procs = JSON.parse(stdout.trim()); - if (!Array.isArray(procs)) { - procs = [procs]; - } - // Find a process with csrf_token in command line - for (const proc of procs) { - const cmd = proc.CommandLine || ''; - const csrfM = cmd.match(/--csrf_token[= ]([^\s"]+)/); - if (csrfM) { - lsPid = proc.ProcessId; - lsCsrf = csrfM[1]; - console.log(`Gravity Bridge: [LS] PID=${lsPid}, CSRF=${lsCsrf.substring(0, 12)}...`); - break; - } - } - } - catch (e) { - console.log(`Gravity Bridge: [LS] parse error: ${e}`); - } - if (!lsPid || !lsCsrf) { - resolve(false); - return; - } - // Phase 2: netstat → find LS listening ports - cp.exec(`netstat -ano | findstr "LISTENING" | findstr " ${lsPid}"`, { maxBuffer: 512 * 1024 }, async (err2, stdout2) => { - if (err2 || !stdout2.trim()) { - console.log(`Gravity Bridge: [LS] no listening ports found for PID ${lsPid}`); - resolve(false); - return; - } - // Parse ports - const ports = []; - for (const line of stdout2.split('\n')) { - const m = line.match(/:(\d+)\s+.*LISTENING/); - if (m) { - ports.push(parseInt(m[1])); - } - } - const uniquePorts = [...new Set(ports)].sort((a, b) => a - b); - console.log(`Gravity Bridge: [LS] ports for PID ${lsPid}: ${uniquePorts.join(', ')}`); - // Try ConnectRPC probe on each port (HTTP first, then HTTPS) - for (const port of uniquePorts) { - const ok = await probeLSPort(port); - if (ok) { - lsPort = port; - console.log(`Gravity Bridge: [LS] ✅ ConnectRPC active on port ${port}`); - resolve(true); - return; - } - } - console.log(`Gravity Bridge: [LS] no ConnectRPC port responded`); - resolve(false); - }); - }); - }); - } - function probeLSPort(port) { - return new Promise((resolve) => { - const http = require('http'); - const https = require('https'); - // Try HTTP first (extension_server uses HTTP) - const tryProto = (proto, useTls) => { - const req = proto.request({ - hostname: '127.0.0.1', - port, - path: '/exa.language_server_pb.LanguageServerService/Heartbeat', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-codeium-csrf-token': lsCsrf, - }, - rejectUnauthorized: false, - timeout: 2000, - }, (res) => { - let data = ''; - res.on('data', (chunk) => { data += chunk; }); - res.on('end', () => { - console.log(`Gravity Bridge: [LS] port ${port} (${useTls ? 'https' : 'http'}) status=${res.statusCode} body=${data.substring(0, 200)}`); - // If HTTP got "HTTPS server" response, retry with HTTPS - if (!useTls && data.includes('HTTPS server')) { - tryProto(https, true); - return; - } - if (res.statusCode !== 404) { - lsUseTls = useTls; // remember which protocol worked - } - resolve(res.statusCode !== 404); - }); - }); - req.on('error', () => { - if (!useTls) { - // Try HTTPS - tryProto(https, true); - } - else { - resolve(false); - } - }); - req.on('timeout', () => { req.destroy(); resolve(false); }); - req.write('{}'); - req.end(); - }; - tryProto(http, false); - }); - } - async function lsRPC(method, payload = {}) { - if (!lsPort || !lsCsrf) { - return null; - } - return new Promise((resolve) => { - const http = require('http'); - const https = require('https'); - const proto = lsUseTls ? https : http; // use detected protocol - const body = JSON.stringify(payload); - const req = proto.request({ - hostname: '127.0.0.1', - port: lsPort, - path: `/exa.language_server_pb.LanguageServerService/${method}`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-codeium-csrf-token': lsCsrf, - 'Content-Length': Buffer.byteLength(body), - }, - rejectUnauthorized: false, - timeout: 5000, - }, (res) => { - let data = ''; - res.on('data', (chunk) => { data += chunk; }); - res.on('end', () => { - try { - resolve(JSON.parse(data)); - } - catch { - resolve(data); - } - }); - }); - req.on('error', (e) => { - console.log(`Gravity Bridge: [LS RPC] ${method} error: ${e.message}`); - resolve(null); - }); - req.on('timeout', () => { req.destroy(); resolve(null); }); - req.write(body); - req.end(); - }); - } - let pollFailCount = 0; - let pollCount = 0; - async function pollConversations() { - if (!lsPort) { - return; - } - if (pollFailCount > 10) { - return; - } // stop after repeated failures - pollCount++; - try { - // Use getDiagnostics to get cascade-level conversation IDs - const diag = await vscode.commands.executeCommand('antigravity.getDiagnostics'); - if (!diag) { - return; - } - const parsed = typeof diag === 'string' ? JSON.parse(diag) : diag; - const trajectories = parsed.recentTrajectories || []; - if (!Array.isArray(trajectories) || trajectories.length === 0) { - return; - } - const isFirstPoll = Object.keys(lastStepIndex).length === 0; - if (isFirstPoll) { - console.log(`Gravity Bridge: [LS] ${trajectories.length} trajectories from getDiagnostics`); - } - // Periodic debug every ~1 min (12 * 5s) - if (pollCount % 12 === 0) { - const summary = trajectories.map((t) => { - const id = (t.googleAgentId || '').substring(0, 8); - return `${id}:s${t.lastStepIndex ?? '?'}`; - }).join(', '); - console.log(`Gravity Bridge: [LS] poll#${pollCount} — ${trajectories.length} trajs: [${summary}]`); - } - // Check ALL trajectories for step count changes - for (const traj of trajectories) { - const agentId = traj.googleAgentId || ''; - const trajId = traj.trajectoryId || ''; - const stepIdx = traj.lastStepIndex ?? 0; - const summary = traj.summary || ''; - if (!agentId && !trajId) { - continue; - } - const key = agentId || trajId; - const prev = lastStepIndex[key]; - if (prev === undefined) { - // First time seeing this trajectory — initialize - lastStepIndex[key] = stepIdx; - if (isFirstPoll) { - console.log(`Gravity Bridge: [LS] init ${key.substring(0, 8)} at step ${stepIdx} "${summary.substring(0, 30)}"`); - } - else if (stepIdx > 0 && summary) { - // New conversation with AI response! - console.log(`Gravity Bridge: [LS] NEW conversation ${key.substring(0, 8)} at step ${stepIdx} "${summary.substring(0, 40)}"`); - subscribeToStream(key); - // Try to extract AI text from extensionLogs - const aiText = extractFromLogs(parsed); - if (aiText) { - writeChatSnapshot(aiText); - console.log(`Gravity Bridge: [LS] → relayed AI text (${aiText.length} chars) from logs`); - } - else { - writeChatSnapshot(`**${summary}**\n\n(새 대화, step ${stepIdx})`); - console.log(`Gravity Bridge: [LS] → summary fallback to Discord`); - } - lastStepIndex[key + '_summary'] = summary; - } - continue; - } - if (stepIdx > prev) { - // Existing conversation has new steps - console.log(`Gravity Bridge: [LS] ${key.substring(0, 8)} steps: ${prev} → ${stepIdx} "${summary.substring(0, 40)}"`); - // Try to extract AI text from extensionLogs - const aiText = extractFromLogs(parsed); - if (aiText) { - writeChatSnapshot(aiText); - console.log(`Gravity Bridge: [LS] → relayed AI text (${aiText.length} chars)`); - } - else if (summary && summary !== lastStepIndex[key + '_summary']) { - // Summary changed = new topic - writeChatSnapshot(`**${summary}**\n\n(step ${prev} → ${stepIdx})`); - console.log(`Gravity Bridge: [LS] → summary change relayed`); - } - lastStepIndex[key + '_summary'] = summary; - lastStepIndex[key] = stepIdx; - } - } - } - catch (e) { - console.log(`Gravity Bridge: [LS poll] error: ${e}`); - } - } - function extractAndRelaySteps(steps) { - const messages = []; - for (const step of steps) { - // Try every possible way to find AI text in a step - const type = step.type || step.stepType || step.step_type || ''; - const content = step.content || step.summary || step.text || step.message || ''; - // PlannerResponse = AI's text output to user - if (content && (type.includes('Response') || type.includes('response') || - type.includes('Message') || type.includes('message') || - type.includes('Notify') || type.includes('notify'))) { - messages.push(content); - continue; - } - // Check nested data/content - if (step.data?.content && typeof step.data.content === 'string') { - messages.push(step.data.content); - continue; - } - // Check role-based (assistant messages) - if ((step.role === 'assistant' || step.role === 'model') && content) { - messages.push(content); - continue; - } - // Catch-all: any string content longer than 20 chars that's not a tool call - if (typeof content === 'string' && content.length > 20 && - !type.includes('Tool') && !type.includes('tool') && - !type.includes('Command') && !type.includes('command')) { - messages.push(content); - } - } - if (messages.length > 0) { - const combined = messages.join('\n\n---\n\n'); - writeChatSnapshot(combined); - console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) (${combined.length} chars) to Discord`); - } - } - function extractFromLogs(diagData) { - // Try to find AI response text in extension logs - const logs = diagData.extensionLogs || diagData.extension_logs || ''; - if (!logs || typeof logs !== 'string' || logs.length < 10) { - return null; - } - // Look for patterns that indicate AI response text - // Pattern 1: notify_user Message content - const notifyMatch = logs.match(/notify_user.*?"Message"\s*:\s*"([^"]{20,})"/s); - if (notifyMatch) { - return notifyMatch[1]; - } - // Pattern 2: "content": "..." blocks from assistant role - const contentMatches = logs.match(/"content"\s*:\s*"([^"]{50,})"/g); - if (contentMatches && contentMatches.length > 0) { - const lastContent = contentMatches[contentMatches.length - 1]; - const m = lastContent.match(/"content"\s*:\s*"(.+)"/); - if (m) { - return m[1].replace(/\\n/g, '\n').replace(/\\"/g, '"'); - } - } - // Pattern 3: Look for Korean text blocks (likely user-facing response) - const koreanBlocks = logs.match(/[\uAC00-\uD7A3]{10,}[^"]{0,200}/g); - if (koreanBlocks && koreanBlocks.length > 0) { - return koreanBlocks[koreanBlocks.length - 1].substring(0, 500); - } - return null; - } - // ========== Trial E2: Electron webContents probe ========== - setTimeout(() => { - console.log('Gravity Bridge: [Trial E2] Probing Electron webContents...'); - try { - // Try to access Electron APIs from extension host - const electron = require('electron'); - console.log(`Gravity Bridge: [Trial E2] electron keys: ${Object.keys(electron).join(', ')}`); - // Try remote (deprecated but might work) - if (electron.remote) { - const wcs = electron.remote.webContents.getAllWebContents(); - console.log(`Gravity Bridge: [Trial E2] Found ${wcs.length} webContents via remote`); - wcs.forEach((wc, i) => { - console.log(` [${i}] id=${wc.id} url=${wc.getURL().substring(0, 80)} title=${wc.getTitle().substring(0, 40)}`); - }); - } - } - catch (e) { - console.log(`Gravity Bridge: [Trial E2] electron: ${e.message}`); - } - try { - // Try @electron/remote - const remote = require('@electron/remote'); - const wcs = remote.webContents.getAllWebContents(); - console.log(`Gravity Bridge: [Trial E2] @electron/remote: ${wcs.length} webContents`); - } - catch (e) { - console.log(`Gravity Bridge: [Trial E2] @electron/remote: ${e.message}`); - } - try { - // Try process.mainModule to access main process - const mainModule = process.mainModule; - console.log(`Gravity Bridge: [Trial E2] mainModule: ${mainModule?.filename?.substring(0, 80)}`); - } - catch (e) { - console.log(`Gravity Bridge: [Trial E2] mainModule: ${e.message}`); - } - // Try to find webview frames via VS Code internals - try { - const vscodeInternal = global._VSCODE_NODE_MODULES; - if (vscodeInternal) { - console.log(`Gravity Bridge: [Trial E2] _VSCODE_NODE_MODULES keys: ${Object.keys(vscodeInternal).join(', ')}`); - } - } - catch (e) { - console.log(`Gravity Bridge: [Trial E2] vscode internals: ${e.message}`); - } - // Try to list all vscode webview panels through undocumented APIs - try { - const allCmds = ['workbench.action.webview.openDeveloperTools', 'workbench.experimental.chat.dump']; - allCmds.forEach(async (cmd) => { - try { - const result = await vscode.commands.executeCommand(cmd); - console.log(`Gravity Bridge: [Trial E2] ${cmd}: ${JSON.stringify(result).substring(0, 300)}`); - } - catch (e) { - console.log(`Gravity Bridge: [Trial E2] ${cmd}: ${e.message}`); - } - }); - } - catch (e) { } - }, 8000); - // ========== Stream subscription for active cascades ========== - function subscribeToStream(cascadeId) { - if (!lsPort || !lsCsrf) { - return; - } - const http = require('http'); - console.log(`Gravity Bridge: [Stream] Subscribing to cascade ${cascadeId.substring(0, 8)}...`); - const gidBuf = Buffer.from(cascadeId, 'utf-8'); - // field1=version(varint=1), field2=cascadeId(string) - const proto = Buffer.alloc(2 + 2 + gidBuf.length); - proto[0] = 0x08; - proto[1] = 0x01; - proto[2] = 0x12; - proto[3] = gidBuf.length; - gidBuf.copy(proto, 4); - // ConnectRPC frame - const frame = Buffer.alloc(5 + proto.length); - frame[0] = 0x00; - frame.writeUInt32BE(proto.length, 1); - proto.copy(frame, 5); - const req = http.request({ - hostname: '127.0.0.1', port: lsPort, - path: '/exa.language_server_pb.LanguageServerService/StreamCascadeReactiveUpdates', - method: 'POST', - headers: { - 'Content-Type': 'application/connect+proto', - 'Connect-Protocol-Version': '1', - 'x-codeium-csrf-token': lsCsrf, - }, - timeout: 30000 - }, (res) => { - console.log(`Gravity Bridge: [Stream] Connected! status=${res.statusCode}`); - let totalBytes = 0; - const allChunks = []; - res.on('data', (chunk) => { - allChunks.push(chunk); - totalBytes += chunk.length; - // Log each chunk as it arrives (real-time streaming) - const text = chunk.toString('utf-8'); - console.log(`Gravity Bridge: [Stream] chunk (${chunk.length}B): ${text.substring(0, 300)}`); - }); - res.on('end', () => { - const fullBuf = Buffer.concat(allChunks); - const fullText = fullBuf.toString('utf-8'); - console.log(`Gravity Bridge: [Stream] Ended. Total ${totalBytes}B in ${allChunks.length} chunks`); - // Try to extract readable text from the stream data - // Look for strings in the protobuf data - const readable = fullText.replace(/[\x00-\x1F\x7F-\x9F]/g, ' ').replace(/\s+/g, ' ').trim(); - if (readable.length > 20) { - console.log(`Gravity Bridge: [Stream] Readable: ${readable.substring(0, 1000)}`); - } - // Check for error messages - if (fullText.includes('"error"')) { - console.log(`Gravity Bridge: [Stream] Error in response: ${fullText.substring(0, 500)}`); - } - }); - }); - req.on('error', (e) => console.log(`Gravity Bridge: [Stream] Error: ${e.message}`)); - req.on('timeout', () => { - console.log(`Gravity Bridge: [Stream] Timeout (30s) — closing`); - req.destroy(); - }); - req.write(frame); - req.end(); - } - // Start LS bridge after a delay - setTimeout(async () => { - const found = await discoverLS(); - if (found) { - console.log(`Gravity Bridge: [LS] bridge active — polling every 5s`); - // Initialize step counts - await pollConversations(); - // Start polling loop - setInterval(pollConversations, 5000); - } - else { - console.log(`Gravity Bridge: [LS] bridge NOT available — AI responses won't relay`); - } - }, 8000); - // Chat document change listener — captures AI text responses - context.subscriptions.push(vscode.workspace.onDidChangeTextDocument((event) => { - handleChatDocumentChange(event); - })); - // Register @bridge Chat Participant for history relay - try { - const participant = vscode.chat.createChatParticipant('gravity-bridge.gravity', bridgeChatHandler); - participant.iconPath = new vscode.ThemeIcon('radio-tower'); - context.subscriptions.push(participant); - console.log('Gravity Bridge: @bridge chat participant registered'); - } - catch (err) { - console.log('Gravity Bridge: chat participant API not available (OK)'); - } - // Auto-watch brain/ for new conversations → auto-register - watchBrainForNewSessions(); - // Auto-start - startBridge(); } -function startBridge() { - if (isActive) { - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): already running`); - return; - } - isActive = true; - statusBar.text = `$(radio-tower) ${projectName}: On`; - statusBar.tooltip = `Gravity Bridge — ${projectName} (Active)`; - statusBar.command = 'gravityBridge.stop'; - // Watch bridge/response/ for Discord user responses - const responsePath = path.join(bridgePath, 'response'); - const processedFiles = new Set(); // Debounce +function writeChatSnapshot(text) { try { - watcher = fs.watch(responsePath, { persistent: false }, (eventType, filename) => { - if (filename && filename.endsWith('.json') && !processedFiles.has(filename)) { - processedFiles.add(filename); - setTimeout(() => processedFiles.delete(filename), 2000); - handleResponse(path.join(responsePath, filename)); - } - }); - console.log('Gravity Bridge: watching response directory'); + 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 (err) { - console.error('Gravity Bridge: failed to watch response dir', err); + catch (e) { + console.log(`Gravity Bridge: snapshot write error: ${e.message}`); } - // Watch for commands (user text input from Discord) - const commandsPath = path.join(bridgePath, 'commands'); - try { - commandsWatcher = fs.watch(commandsPath, { persistent: false }, (eventType, filename) => { - if (filename && filename.endsWith('.json') && !processedFiles.has(filename)) { - processedFiles.add(filename); - setTimeout(() => processedFiles.delete(filename), 2000); - handleCommand(path.join(commandsPath, filename)); - } - }); - console.log('Gravity Bridge: watching commands directory'); - } - catch (err) { - console.error('Gravity Bridge: failed to watch commands dir', err); - } - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): Started`); - console.log(`Gravity Bridge: started for project "${projectName}", bridge: ${bridgePath}`); } -function stopBridge() { - if (!isActive) { - return; - } - isActive = false; - statusBar.text = `$(radio-tower) ${projectName}: Off`; - statusBar.tooltip = `Gravity Bridge — ${projectName}`; - statusBar.command = 'gravityBridge.start'; - if (watcher) { - watcher.close(); - watcher = null; - } - if (commandsWatcher) { - commandsWatcher.close(); - commandsWatcher = null; - } - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): Stopped`); -} -/** - * Handle a response from Discord (approve/reject). - * Only processes responses — no project filtering needed since request_id is unique. - */ -async function handleResponse(filePath) { +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 { - await new Promise(resolve => setTimeout(resolve, 200)); - if (!fs.existsSync(filePath)) { - return; - } const content = fs.readFileSync(filePath, 'utf-8'); - const response = JSON.parse(content); - if (response.approved === undefined) { + 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 [${projectName}]: response — approved=${response.approved}`); - if (response.approved) { - await simulateApproval(); - vscode.window.showInformationMessage(`✅ Approved: ${response.request_id}`); + 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 { - await simulateRejection(); - vscode.window.showInformationMessage(`❌ Rejected: ${response.request_id}`); + 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 (e) { /* ignore */ } + catch { } } - catch (err) { - console.error('Gravity Bridge: error handling response', err); + catch (e) { + console.log(`Gravity Bridge: command processing error: ${e.message}`); } } -/** - * Handle a text command from Discord. - * ONLY processes commands matching this project's name. - */ -async function handleCommand(filePath) { +function watchCommandsDir() { + const cmdDir = path.join(bridgePath, 'commands'); + // Process existing files try { - await new Promise(resolve => setTimeout(resolve, 200)); - if (!fs.existsSync(filePath)) { - return; - } - const content = fs.readFileSync(filePath, 'utf-8'); - const command = JSON.parse(content); - if (command.consumed || !command.text) { - return; - } - // ★ PROJECT FILTER — only process commands for THIS project - const cmdProject = command.project_name || ''; - if (cmdProject && cmdProject !== projectName) { - console.log(`Gravity Bridge [${projectName}]: skipping command for "${cmdProject}"`); - return; // Not for us — leave file for the correct Extension instance - } - const text = command.text.trim(); - console.log(`Gravity Bridge [${projectName}]: command — "${text.substring(0, 50)}"`); - // Special command: !stop — cancel AI work - if (text === '!stop') { - try { - await vscode.commands.executeCommand('workbench.action.chat.stop'); - vscode.window.showWarningMessage(`⏹️ [${projectName}] AI 작업 중지됨`); + for (const f of fs.readdirSync(cmdDir)) { + if (f.endsWith('.json')) { + processCommandFile(path.join(cmdDir, f)); } - catch { - vscode.window.showErrorMessage('AI 중지 명령 실행 실패'); - } - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - return; } - // Special command: auto-approve toggle - if (text === '!auto on' || text === '!auto off') { - const enabled = text === '!auto on'; - await toggleAutoApprove(enabled); - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - return; - } - // General text: send directly to Antigravity agent panel - try { - await vscode.commands.executeCommand('antigravity.sendPromptToAgentPanel', command.text); - console.log(`Gravity Bridge: ✅ sent via sendPromptToAgentPanel`); - } - catch (e1) { - console.log(`Gravity Bridge: sendPromptToAgentPanel failed: ${e1}`); - // Fallback: try sendChatActionMessage - try { - await vscode.commands.executeCommand('antigravity.sendChatActionMessage', command.text); - console.log(`Gravity Bridge: ✅ sent via sendChatActionMessage`); - } - catch (e2) { - console.log(`Gravity Bridge: sendChatActionMessage failed: ${e2}`); - // Last resort: focus panel + clipboard paste - try { - await vscode.commands.executeCommand('antigravity.agentPanel.focus'); - await new Promise(resolve => setTimeout(resolve, 300)); - const oldClip = await vscode.env.clipboard.readText(); - await vscode.env.clipboard.writeText(command.text); - await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); - await vscode.env.clipboard.writeText(oldClip); - console.log('Gravity Bridge: clipboard paste fallback'); + } + 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 (e3) { - console.error('Gravity Bridge: all methods failed', e3); + } + }); + } + catch { } +} +// ─── SDK Integration ─── +async function initSDK(context) { + try { + const sdkModule = require('antigravity-sdk'); + 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; } } } - // Always mark as consumed - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - } - catch (err) { - console.error('Gravity Bridge: error handling command', err); - } + 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)'); } -/** - * Toggle Antigravity's auto-approve settings. - */ -async function toggleAutoApprove(enabled) { - const config = vscode.workspace.getConfiguration(); - try { - await config.update('chat.tools.autoApprove', enabled, vscode.ConfigurationTarget.Global); - await config.update('chat.agent.autoApprove', enabled, vscode.ConfigurationTarget.Global); - if (enabled) { - await config.update('chat.tools.terminal.enableAutoApprove', true, vscode.ConfigurationTarget.Global); - } - await config.update('autoAcceptV2.autoAcceptFileEdits', enabled, vscode.ConfigurationTarget.Global); - statusBar.text = enabled - ? `$(radio-tower) ${projectName}: Auto ✅` - : `$(radio-tower) ${projectName}: Manual 🔒`; - const mode = enabled ? '자동 승인 ON 🟢' : '수동 승인 OFF 🔴'; - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): ${mode}`); - const statusPath = path.join(bridgePath, 'commands', `auto-status-${Date.now()}.json`); - fs.writeFileSync(statusPath, JSON.stringify({ - id: `auto-status-${Date.now()}`, - project_name: projectName, - text: `[SYSTEM] Auto-approve: ${enabled ? 'ON' : 'OFF'}`, - timestamp: Date.now() / 1000, - consumed: true, - auto_approve: enabled, - }, null, 2), 'utf-8'); - } - catch (err) { - console.error('Gravity Bridge: failed to toggle auto-approve', err); - } -} -async function simulateApproval() { - try { - await vscode.commands.executeCommand('workbench.action.acceptSelectedCodeAction'); - } - catch { - try { - await vscode.commands.executeCommand('type', { text: '\n' }); - } - catch { - await vscode.commands.executeCommand('workbench.action.terminal.focus'); - } - } -} -async function simulateRejection() { - try { - await vscode.commands.executeCommand('workbench.action.closeQuickOpen'); - } - catch { - try { - await vscode.commands.executeCommand('cancelSelection'); - } - catch { - console.log('Gravity Bridge: rejection sent but no active dialog found'); - } - } -} -/** - * Manual approve/reject from command palette. - */ -function handleManualAction(approved) { - const requestId = `manual-${Date.now()}`; - const responsePath = path.join(bridgePath, 'response', `${requestId}.json`); - const response = { - request_id: requestId, - approved: approved, - user_input: '', - timestamp: Date.now() / 1000, - }; - fs.writeFileSync(responsePath, JSON.stringify(response, null, 2), 'utf-8'); - if (approved) { - simulateApproval(); +// ─── 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 { - simulateRejection(); + statusBar.text = '$(warning) Bridge (no SDK)'; + console.log('Gravity Bridge: SDK not available, file-based mode only'); } -} -/** - * Write a pending approval request to bridge/pending/ for Discord bot to pick up. - * Includes project_name for correct channel routing. - */ -function writePendingApproval(conversationId, command, description) { - const requestId = `req-${Date.now()}`; - const pendingPath = path.join(bridgePath, 'pending', `${requestId}.json`); - const request = { - request_id: requestId, - conversation_id: conversationId, - project_name: projectName, // ★ Project routing - command: command, - description: description, - timestamp: Date.now() / 1000, - status: 'pending', - discord_message_id: 0, - }; - fs.writeFileSync(pendingPath, JSON.stringify(request, null, 2), 'utf-8'); - sentPendingIds.add(requestId); - console.log(`Gravity Bridge [${projectName}]: pending approval — ${requestId}`); - return requestId; -} -/** - * Register a conversation → project mapping in bridge/register/. - * The bot reads these files to route brain events to the correct channel. - */ -function registerConversation(conversationId) { - const registerDir = path.join(bridgePath, 'register'); - if (!fs.existsSync(registerDir)) { - fs.mkdirSync(registerDir, { recursive: true }); - } - const filePath = path.join(registerDir, `${conversationId}.json`); - const data = { - conversation_id: conversationId, - project_name: projectName, - timestamp: Date.now() / 1000, - }; - fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); - console.log(`Gravity Bridge [${projectName}]: registered ${conversationId.substring(0, 8)}`); -} -/** - * Read the title (first # heading) from a conversation's task.md or implementation_plan.md. - */ -function getConversationTitle(convDir) { - for (const fname of ['task.md', 'implementation_plan.md']) { - const fpath = path.join(convDir, fname); - if (fs.existsSync(fpath)) { - try { - const lines = fs.readFileSync(fpath, 'utf-8').split('\n').slice(0, 5); - for (const line of lines) { - const match = line.match(/^#\s+(.+)/); - if (match) { - return match[1].trim().substring(0, 50); - } - } - } - catch { /* ignore */ } + // 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(); } - } - return ''; -} -/** - * Manual connect: scan brain/ for recent conversations and let user pick. - * Shows task.md titles for readability. Offers auto-connect for new projects. - */ -async function connectSession() { - const brainPath = path.join(os.homedir(), '.gemini', 'antigravity', 'brain'); - if (!fs.existsSync(brainPath)) { - vscode.window.showErrorMessage('Brain 디렉토리를 찾을 수 없습니다.'); - return; - } - // Get conversation dirs sorted by modification time (newest first) - const dirs = fs.readdirSync(brainPath) - .filter(d => { - const fullPath = path.join(brainPath, d); - return fs.statSync(fullPath).isDirectory() && d.includes('-'); - }) - .map(d => { - const fullPath = path.join(brainPath, d); - return { - name: d, - mtime: fs.statSync(fullPath).mtimeMs, - title: getConversationTitle(fullPath), - }; - }) - .sort((a, b) => b.mtime - a.mtime) - .slice(0, 10); - // Build QuickPick items - const items = []; - // Always offer auto-connect option first - items.push({ - label: '$(sync) 새 대화 자동 연결', - description: '다음에 시작하는 대화가 자동으로 이 프로젝트에 연결됩니다', - detail: `프로젝트: ${projectName}`, - }); - // Add conversation items with titles - for (const d of dirs) { - const titleLabel = d.title || '(제목 없음)'; - const timeStr = new Date(d.mtime).toLocaleString(); - items.push({ - label: `$(comment-discussion) ${titleLabel}`, - description: d.name.substring(0, 8), - detail: `${d.name} · ${timeStr}`, - convId: d.name, - }); - } - const selected = await vscode.window.showQuickPick(items, { - placeHolder: `프로젝트 "${projectName}"에 연결할 세션을 선택하세요`, - }); - if (!selected) { - return; - } - if (!('convId' in selected) || !selected.convId) { - // Auto-connect mode - vscode.window.showInformationMessage(`🔄 ${projectName}: 다음 대화가 자동으로 연결됩니다`); - return; - } - registerConversation(selected.convId); - vscode.window.showInformationMessage(`✅ ${selected.description} → ${projectName} 연결됨`); -} -/** - * Auto-watch brain/ for new conversation directories → auto-register. - */ -function watchBrainForNewSessions() { - const brainPath = path.join(os.homedir(), '.gemini', 'antigravity', 'brain'); - if (!fs.existsSync(brainPath)) { - return; - } - // Track known dirs - const knownDirs = new Set(fs.readdirSync(brainPath).filter(d => fs.statSync(path.join(brainPath, d)).isDirectory())); - try { - fs.watch(brainPath, { persistent: false }, (eventType, filename) => { - if (!filename || !filename.includes('-')) { - return; - } - const fullPath = path.join(brainPath, filename); - // Check if it's a new directory - if (!knownDirs.has(filename) && fs.existsSync(fullPath) && - fs.statSync(fullPath).isDirectory()) { - knownDirs.add(filename); - registerConversation(filename); - console.log(`Gravity Bridge [${projectName}]: auto-registered new session ${filename.substring(0, 8)}`); - } - }); - console.log(`Gravity Bridge [${projectName}]: watching brain/ for new sessions`); - } - catch (err) { - console.error('Gravity Bridge: failed to watch brain dir', err); - } -} -/** - * Monitor text document changes for chat panel content. - * VS Code chat documents have special URI schemes (vscode-chat-response, etc.). - * We capture significant changes and relay to Discord. - */ -let lastChatContent = ''; -let chatDebounceTimer = null; -function handleChatDocumentChange(event) { - const doc = event.document; - const scheme = doc.uri.scheme; - // Log ALL schemes to discover chat-related ones (debug mode) - if (scheme !== 'file' && scheme !== 'git' && scheme !== 'output' && - scheme !== 'vscode-userdata' && scheme !== 'untitled') { - console.log(`Gravity Bridge [${projectName}]: doc change scheme="${scheme}" uri="${doc.uri.toString().substring(0, 80)}"`); - } - // Capture chat-related documents - // Known chat schemes: vscode-chat-response, vscode-copilot-chat, etc. - const isChatDoc = scheme.includes('chat') || scheme.includes('copilot') || - scheme.includes('notebook') || doc.uri.path.includes('chat'); - if (!isChatDoc) { - return; - } - const content = doc.getText(); - if (!content || content === lastChatContent) { - return; - } - // Debounce: wait 2s for content to stabilize (AI streams text) - if (chatDebounceTimer) { - clearTimeout(chatDebounceTimer); - } - chatDebounceTimer = setTimeout(() => { - const finalContent = doc.getText(); - if (finalContent && finalContent !== lastChatContent && finalContent.length > 20) { - lastChatContent = finalContent; - writeChatSnapshot(finalContent); + 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; } - }, 2000); -} -/** - * Write a chat content snapshot to bridge for the bot to relay. - */ -function writeChatSnapshot(content) { - const snapshotDir = path.join(bridgePath, 'chat_snapshots'); - if (!fs.existsSync(snapshotDir)) { - fs.mkdirSync(snapshotDir, { recursive: true }); - } - const id = `chat-${Date.now()}`; - const filePath = path.join(snapshotDir, `${id}.json`); - const data = { - id, - project_name: projectName, - content: content.substring(0, 4000), // Limit size - timestamp: Date.now() / 1000, - }; - fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); - console.log(`Gravity Bridge [${projectName}]: chat snapshot written (${content.length} chars)`); -} -/** - * @bridge Chat Participant handler. - * Reads conversation history and sends to Discord via bridge. - */ -const bridgeChatHandler = async (request, context, stream, token) => { - const command = request.prompt.trim().toLowerCase(); - if (command === 'stop' || command === '중지') { - // Cancel current AI work try { - await vscode.commands.executeCommand('workbench.action.chat.stop'); - stream.markdown('⏹️ AI 작업 중지 요청을 보냈습니다.'); - } - catch { - stream.markdown('⚠️ 중지 명령을 실행할 수 없습니다.'); - } - return; - } - // Collect conversation history - const historyLines = []; - historyLines.push(`# 대화 히스토리 (${projectName})\n`); - for (const entry of context.history) { - if (entry instanceof vscode.ChatRequestTurn) { - historyLines.push(`## 👤 사용자\n${entry.prompt}\n`); - } - else if (entry instanceof vscode.ChatResponseTurn) { - let responseText = ''; - for (const part of entry.response) { - if (part instanceof vscode.ChatResponseMarkdownPart) { - responseText += part.value.value; - } - } - if (responseText) { - historyLines.push(`## 🤖 AI\n${responseText}\n`); + 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}`); } } - } - if (historyLines.length <= 1) { - stream.markdown('대화 히스토리가 비어있습니다. AI와 대화를 먼저 진행한 후 `@bridge`를 호출하세요.'); - return; - } - // Write to bridge for Discord relay - const fullHistory = historyLines.join('\n'); - const cmdId = `bridge-history-${Date.now()}`; - const cmdPath = path.join(bridgePath, 'commands', `${cmdId}.json`); - const data = { - id: cmdId, - project_name: projectName, - text: `[HISTORY]\n${fullHistory}`, - timestamp: Date.now() / 1000, - consumed: false, - }; - fs.writeFileSync(cmdPath, JSON.stringify(data, null, 2), 'utf-8'); - stream.markdown(`✅ 대화 히스토리 (${context.history.length}개 턴)를 Discord에 전송했습니다.`); - console.log(`Gravity Bridge [${projectName}]: sent ${context.history.length} turns to Discord`); -}; + 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() { - stopBridge(); + if (sdk) { + try { + sdk.monitor.stop(); + sdk.dispose(); + } + catch { } + } } //# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/extension/out/extension.js.map b/extension/out/extension.js.map index 0b48878..e7a50cf 100644 --- a/extension/out/extension.js.map +++ b/extension/out/extension.js.map @@ -1 +1 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/extension/src/extension.ts b/extension/src/extension.ts index d66d573..5d510e4 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -1,41 +1,41 @@ /** - * Gravity Bridge — VS Code Extension + * Gravity Bridge — VS Code Extension (SDK Edition) * - * Bridges Antigravity IDE approval dialogs to the Discord bot via file-based protocol. + * 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() * - * Multi-project routing: - * - Each workspace has a project name (from settings or workspace folder name) - * - Extension only processes commands/responses matching its project_name - * - Pending approvals include project_name for Discord channel routing + * Communication with Discord via file-based bridge protocol. */ import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; +import * as cp from 'child_process'; + +// antigravity-sdk is loaded at runtime +let AntigravitySDK: any; +let sdk: any; -let watcher: fs.FSWatcher | null = null; -let commandsWatcher: fs.FSWatcher | null = null; let statusBar: vscode.StatusBarItem; let bridgePath: string; let projectName: string; let isActive = false; +let watcher: fs.FSWatcher | null = null; +let commandsWatcher: fs.FSWatcher | null = null; -// Track pending approvals we've already sent const sentPendingIds = new Set(); -import * as cp from 'child_process'; +// ─── Project Detection ─── -/** - * Detect project name from workspace. - * Priority: settings > git remote repo name > workspace folder name - */ function detectProjectName(): string { const config = vscode.workspace.getConfiguration('gravityBridge'); const configName = config.get('projectName'); if (configName) { return configName; } - // Try git remote URL → extract repo name const folders = vscode.workspace.workspaceFolders; if (folders && folders.length > 0) { const cwd = folders[0].uri.fsPath; @@ -43,1112 +43,311 @@ function detectProjectName(): string { const remoteUrl = cp.execSync('git remote get-url origin', { cwd, encoding: 'utf-8', timeout: 3000 }).trim(); - // "https://gitea.example.com/Variet/gravity_control.git" → "gravity_control" - // "git@github.com:user/repo.git" → "repo" const match = remoteUrl.match(/\/([^\/]+?)(?:\.git)?$/); if (match && match[1]) { - const repoName = match[1].toLowerCase().replace(/[\s\-]+/g, '_'); - console.log(`Gravity Bridge: project from git remote → "${repoName}"`); - return repoName; + return match[1].toLowerCase().replace(/[\s\-]+/g, '_'); } - } catch { - // No git or no remote — fall through - } - - // Fallback: workspace folder name - return folders[0].name.toLowerCase().replace(/[\s\-]+/g, '_'); + } catch { } + return path.basename(cwd).toLowerCase().replace(/[\s\-]+/g, '_'); } - - return 'unknown_project'; + return 'default'; } -export function activate(context: vscode.ExtensionContext) { - projectName = detectProjectName(); - console.log(`Gravity Bridge: activating for project "${projectName}"...`); +// ─── Bridge File I/O ─── - // Determine bridge path +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: string) { + 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: any) { + console.log(`Gravity Bridge: snapshot write error: ${e.message}`); + } +} + +function writePendingApproval(data: any) { + 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: string) { + 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: any) => + console.log(`Gravity Bridge: approve error: ${e.message}`) + ); + } else if (cmd.action === 'reject' && sdk) { + sdk.cascade.rejectStep().catch((e: any) => + console.log(`Gravity Bridge: reject error: ${e.message}`) + ); + } else if (cmd.action === 'approve_terminal' && sdk) { + sdk.cascade.acceptTerminalCommand().catch((e: any) => + 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: any) => { + // 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: any) { + 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: vscode.ExtensionContext): Promise { + try { + const sdkModule = require('antigravity-sdk'); + AntigravitySDK = sdkModule.AntigravitySDK; + } catch (err: any) { + 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: any) { + 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: any) => { + 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: any) => 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: any) => 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: any) { + 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: any) => { + console.log(`Gravity Bridge: [SDK] active session: "${e.title}" (${e.sessionId?.substring(0, 8)})`); + }); + + // State changed (USS update) + sdk.monitor.onStateChanged((e: any) => { + 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 ─── + +export async function activate(context: vscode.ExtensionContext) { + 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'); - - // Ensure bridge directories exist - const dirs = ['pending', 'response', 'commands', 'register']; - for (const dir of dirs) { - const dirPath = path.join(bridgePath, dir); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { recursive: true }); - } - } + ensureBridgeDir(); + console.log(`Gravity Bridge: bridge path: ${bridgePath}`); // Status bar - statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100); - statusBar.command = 'gravityBridge.start'; - statusBar.text = `$(radio-tower) ${projectName}: Off`; - statusBar.tooltip = `Gravity Bridge — ${projectName}`; + statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); + statusBar.text = '$(sync~spin) Bridge'; + statusBar.tooltip = `Gravity Bridge: ${projectName}`; statusBar.show(); context.subscriptions.push(statusBar); - // Register commands - context.subscriptions.push( - vscode.commands.registerCommand('gravityBridge.start', startBridge), - vscode.commands.registerCommand('gravityBridge.stop', stopBridge), - vscode.commands.registerCommand('gravityBridge.connect', connectSession), - vscode.commands.registerCommand('gravityBridge.approve', () => handleManualAction(true)), - vscode.commands.registerCommand('gravityBridge.reject', () => handleManualAction(false)), - ); + // Initialize SDK + const sdkReady = await initSDK(context); - // === LS ConnectRPC Bridge: Relay AI responses to Discord === - let lsPort: number | null = null; - let lsCsrf: string = ''; - let lsPid: number | null = null; - let lsUseTls: boolean = false; // track detected protocol - let lastStepIndex: Record = {}; // cascadeId → last known step index + if (sdkReady) { + setupMonitor(); + statusBar.text = '$(check) Bridge SDK'; + statusBar.tooltip = `Gravity Bridge: ${projectName} (SDK active)`; - async function discoverLS(): Promise { - return new Promise((resolve) => { - // Phase 1: Find LS process → PID + CSRF token - cp.exec( - 'powershell -NoProfile -Command "Get-CimInstance Win32_Process | Where-Object {$_.Name -eq \'language_server_exe.exe\' -or ($_.CommandLine -and $_.CommandLine -like \'*language_server*\' -and $_.CommandLine -notlike \'*powershell*\')} | Select-Object ProcessId, CommandLine | ConvertTo-Json"', - { maxBuffer: 2 * 1024 * 1024 }, - (err, stdout) => { - if (err || !stdout.trim()) { - console.log(`Gravity Bridge: [LS] process not found`); - resolve(false); - return; - } - try { - let procs = JSON.parse(stdout.trim()); - if (!Array.isArray(procs)) { procs = [procs]; } - // Find a process with csrf_token in command line - for (const proc of procs) { - const cmd = proc.CommandLine || ''; - const csrfM = cmd.match(/--csrf_token[= ]([^\s"]+)/); - if (csrfM) { - lsPid = proc.ProcessId; - lsCsrf = csrfM[1]; - console.log(`Gravity Bridge: [LS] PID=${lsPid}, CSRF=${lsCsrf.substring(0, 12)}...`); - break; - } - } - } catch (e) { - console.log(`Gravity Bridge: [LS] parse error: ${e}`); - } - - if (!lsPid || !lsCsrf) { - resolve(false); - return; - } - - // Phase 2: netstat → find LS listening ports - cp.exec( - `netstat -ano | findstr "LISTENING" | findstr " ${lsPid}"`, - { maxBuffer: 512 * 1024 }, - async (err2, stdout2) => { - if (err2 || !stdout2.trim()) { - console.log(`Gravity Bridge: [LS] no listening ports found for PID ${lsPid}`); - resolve(false); - return; - } - // Parse ports - const ports: number[] = []; - for (const line of stdout2.split('\n')) { - const m = line.match(/:(\d+)\s+.*LISTENING/); - if (m) { ports.push(parseInt(m[1])); } - } - const uniquePorts = [...new Set(ports)].sort((a, b) => a - b); - console.log(`Gravity Bridge: [LS] ports for PID ${lsPid}: ${uniquePorts.join(', ')}`); - - // Try ConnectRPC probe on each port (HTTP first, then HTTPS) - for (const port of uniquePorts) { - const ok = await probeLSPort(port); - if (ok) { - lsPort = port; - console.log(`Gravity Bridge: [LS] ✅ ConnectRPC active on port ${port}`); - resolve(true); - return; - } - } - console.log(`Gravity Bridge: [LS] no ConnectRPC port responded`); - resolve(false); - } - ); - } - ); - }); - } - - function probeLSPort(port: number): Promise { - return new Promise((resolve) => { - const http = require('http'); - const https = require('https'); - - // Try HTTP first (extension_server uses HTTP) - const tryProto = (proto: any, useTls: boolean) => { - const req = proto.request({ - hostname: '127.0.0.1', - port, - path: '/exa.language_server_pb.LanguageServerService/Heartbeat', - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-codeium-csrf-token': lsCsrf, - }, - rejectUnauthorized: false, - timeout: 2000, - }, (res: any) => { - let data = ''; - res.on('data', (chunk: any) => { data += chunk; }); - res.on('end', () => { - console.log(`Gravity Bridge: [LS] port ${port} (${useTls ? 'https' : 'http'}) status=${res.statusCode} body=${data.substring(0, 200)}`); - // If HTTP got "HTTPS server" response, retry with HTTPS - if (!useTls && data.includes('HTTPS server')) { - tryProto(https, true); - return; - } - if (res.statusCode !== 404) { - lsUseTls = useTls; // remember which protocol worked - } - resolve(res.statusCode !== 404); - }); - }); - req.on('error', () => { - if (!useTls) { - // Try HTTPS - tryProto(https, true); - } else { - resolve(false); - } - }); - req.on('timeout', () => { req.destroy(); resolve(false); }); - req.write('{}'); - req.end(); - }; - tryProto(http, false); - }); - } - - async function lsRPC(method: string, payload: any = {}): Promise { - if (!lsPort || !lsCsrf) { return null; } - return new Promise((resolve) => { - const http = require('http'); - const https = require('https'); - const proto = lsUseTls ? https : http; // use detected protocol - const body = JSON.stringify(payload); - const req = proto.request({ - hostname: '127.0.0.1', - port: lsPort, - path: `/exa.language_server_pb.LanguageServerService/${method}`, - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-codeium-csrf-token': lsCsrf, - 'Content-Length': Buffer.byteLength(body), - }, - rejectUnauthorized: false, - timeout: 5000, - }, (res: any) => { - let data = ''; - res.on('data', (chunk: any) => { data += chunk; }); - res.on('end', () => { - try { resolve(JSON.parse(data)); } catch { resolve(data); } - }); - }); - req.on('error', (e: any) => { - console.log(`Gravity Bridge: [LS RPC] ${method} error: ${e.message}`); - resolve(null); - }); - req.on('timeout', () => { req.destroy(); resolve(null); }); - req.write(body); - req.end(); - }); - } - - let pollFailCount = 0; - let pollCount = 0; - - async function pollConversations() { - if (!lsPort) { return; } - if (pollFailCount > 10) { return; } // stop after repeated failures - pollCount++; - try { - // Use getDiagnostics to get cascade-level conversation IDs - const diag: any = await vscode.commands.executeCommand('antigravity.getDiagnostics'); - if (!diag) { return; } - - const parsed = typeof diag === 'string' ? JSON.parse(diag) : diag; - const trajectories = parsed.recentTrajectories || []; - if (!Array.isArray(trajectories) || trajectories.length === 0) { return; } - - const isFirstPoll = Object.keys(lastStepIndex).length === 0; - if (isFirstPoll) { - console.log(`Gravity Bridge: [LS] ${trajectories.length} trajectories from getDiagnostics`); - } - - // Periodic debug every ~1 min (12 * 5s) - if (pollCount % 12 === 0) { - const summary = trajectories.map((t: any) => { - const id = (t.googleAgentId || '').substring(0, 8); - return `${id}:s${t.lastStepIndex ?? '?'}`; - }).join(', '); - console.log(`Gravity Bridge: [LS] poll#${pollCount} — ${trajectories.length} trajs: [${summary}]`); - } - - // Check ALL trajectories for step count changes - for (const traj of trajectories) { - const agentId = traj.googleAgentId || ''; - const trajId = traj.trajectoryId || ''; - const stepIdx = traj.lastStepIndex ?? 0; - const summary = traj.summary || ''; - - if (!agentId && !trajId) { continue; } - - const key = agentId || trajId; - const prev = lastStepIndex[key]; - - if (prev === undefined) { - // First time seeing this trajectory — initialize - lastStepIndex[key] = stepIdx; - if (isFirstPoll) { - console.log(`Gravity Bridge: [LS] init ${key.substring(0, 8)} at step ${stepIdx} "${summary.substring(0, 30)}"`); - } else if (stepIdx > 0 && summary) { - // New conversation with AI response! - console.log(`Gravity Bridge: [LS] NEW conversation ${key.substring(0, 8)} at step ${stepIdx} "${summary.substring(0, 40)}"`); - subscribeToStream(key); - // Try to extract AI text from extensionLogs - const aiText = extractFromLogs(parsed); - if (aiText) { - writeChatSnapshot(aiText); - console.log(`Gravity Bridge: [LS] → relayed AI text (${aiText.length} chars) from logs`); - } else { - writeChatSnapshot(`**${summary}**\n\n(새 대화, step ${stepIdx})`); - console.log(`Gravity Bridge: [LS] → summary fallback to Discord`); - } - lastStepIndex[key + '_summary'] = summary; - } - continue; - } - - if (stepIdx > prev) { - // Existing conversation has new steps - console.log(`Gravity Bridge: [LS] ${key.substring(0, 8)} steps: ${prev} → ${stepIdx} "${summary.substring(0, 40)}"`); - - // Try to extract AI text from extensionLogs - const aiText = extractFromLogs(parsed); - if (aiText) { - writeChatSnapshot(aiText); - console.log(`Gravity Bridge: [LS] → relayed AI text (${aiText.length} chars)`); - } else if (summary && summary !== lastStepIndex[key + '_summary']) { - // Summary changed = new topic - writeChatSnapshot(`**${summary}**\n\n(step ${prev} → ${stepIdx})`); - console.log(`Gravity Bridge: [LS] → summary change relayed`); - } - lastStepIndex[key + '_summary'] = summary; - lastStepIndex[key] = stepIdx; - } - } - } catch (e) { - console.log(`Gravity Bridge: [LS poll] error: ${e}`); - } - } - - - - - function extractAndRelaySteps(steps: any[]) { - const messages: string[] = []; - - for (const step of steps) { - // Try every possible way to find AI text in a step - const type = step.type || step.stepType || step.step_type || ''; - const content = step.content || step.summary || step.text || step.message || ''; - - // PlannerResponse = AI's text output to user - if (content && ( - type.includes('Response') || type.includes('response') || - type.includes('Message') || type.includes('message') || - type.includes('Notify') || type.includes('notify') - )) { - messages.push(content); - continue; - } - - // Check nested data/content - if (step.data?.content && typeof step.data.content === 'string') { - messages.push(step.data.content); - continue; - } - - // Check role-based (assistant messages) - if ((step.role === 'assistant' || step.role === 'model') && content) { - messages.push(content); - continue; - } - - // Catch-all: any string content longer than 20 chars that's not a tool call - if (typeof content === 'string' && content.length > 20 && - !type.includes('Tool') && !type.includes('tool') && - !type.includes('Command') && !type.includes('command')) { - messages.push(content); - } - } - - if (messages.length > 0) { - const combined = messages.join('\n\n---\n\n'); - writeChatSnapshot(combined); - console.log(`Gravity Bridge: [LS] relayed ${messages.length} response(s) (${combined.length} chars) to Discord`); - } - } - - function extractFromLogs(diagData: any): string | null { - // Try to find AI response text in extension logs - const logs = diagData.extensionLogs || diagData.extension_logs || ''; - if (!logs || typeof logs !== 'string' || logs.length < 10) { return null; } - - // Look for patterns that indicate AI response text - // Pattern 1: notify_user Message content - const notifyMatch = logs.match(/notify_user.*?"Message"\s*:\s*"([^"]{20,})"/s); - if (notifyMatch) { return notifyMatch[1]; } - - // Pattern 2: "content": "..." blocks from assistant role - const contentMatches = logs.match(/"content"\s*:\s*"([^"]{50,})"/g); - if (contentMatches && contentMatches.length > 0) { - const lastContent = contentMatches[contentMatches.length - 1]; - const m = lastContent.match(/"content"\s*:\s*"(.+)"/); - if (m) { return m[1].replace(/\\n/g, '\n').replace(/\\"/g, '"'); } - } - - // Pattern 3: Look for Korean text blocks (likely user-facing response) - const koreanBlocks = logs.match(/[\uAC00-\uD7A3]{10,}[^"]{0,200}/g); - if (koreanBlocks && koreanBlocks.length > 0) { - return koreanBlocks[koreanBlocks.length - 1].substring(0, 500); - } - - return null; - } - - - - - // ========== Trial E2: Electron webContents probe ========== - setTimeout(() => { - console.log('Gravity Bridge: [Trial E2] Probing Electron webContents...'); - try { - // Try to access Electron APIs from extension host - const electron = require('electron'); - console.log(`Gravity Bridge: [Trial E2] electron keys: ${Object.keys(electron).join(', ')}`); - - // Try remote (deprecated but might work) - if (electron.remote) { - const wcs = electron.remote.webContents.getAllWebContents(); - console.log(`Gravity Bridge: [Trial E2] Found ${wcs.length} webContents via remote`); - wcs.forEach((wc: any, i: number) => { - console.log(` [${i}] id=${wc.id} url=${wc.getURL().substring(0, 80)} title=${wc.getTitle().substring(0, 40)}`); - }); - } - } catch (e: any) { console.log(`Gravity Bridge: [Trial E2] electron: ${e.message}`); } - - try { - // Try @electron/remote - const remote = require('@electron/remote'); - const wcs = remote.webContents.getAllWebContents(); - console.log(`Gravity Bridge: [Trial E2] @electron/remote: ${wcs.length} webContents`); - } catch (e: any) { console.log(`Gravity Bridge: [Trial E2] @electron/remote: ${e.message}`); } - - try { - // Try process.mainModule to access main process - const mainModule = process.mainModule; - console.log(`Gravity Bridge: [Trial E2] mainModule: ${mainModule?.filename?.substring(0, 80)}`); - } catch (e: any) { console.log(`Gravity Bridge: [Trial E2] mainModule: ${e.message}`); } - - // Try to find webview frames via VS Code internals - try { - const vscodeInternal = (global as any)._VSCODE_NODE_MODULES; - if (vscodeInternal) { - console.log(`Gravity Bridge: [Trial E2] _VSCODE_NODE_MODULES keys: ${Object.keys(vscodeInternal).join(', ')}`); - } - } catch (e: any) { console.log(`Gravity Bridge: [Trial E2] vscode internals: ${e.message}`); } - - // Try to list all vscode webview panels through undocumented APIs - try { - const allCmds = ['workbench.action.webview.openDeveloperTools', 'workbench.experimental.chat.dump']; - allCmds.forEach(async (cmd) => { + // Register SDK-powered commands + context.subscriptions.push( + vscode.commands.registerCommand('gravityBridge.approve', async () => { try { - const result = await vscode.commands.executeCommand(cmd); - console.log(`Gravity Bridge: [Trial E2] ${cmd}: ${JSON.stringify(result).substring(0, 300)}`); - } catch (e: any) { console.log(`Gravity Bridge: [Trial E2] ${cmd}: ${e.message}`); } - }); - } catch (e: any) { } - - }, 8000); - - // ========== Stream subscription for active cascades ========== - function subscribeToStream(cascadeId: string): void { - if (!lsPort || !lsCsrf) { return; } - const http = require('http'); - console.log(`Gravity Bridge: [Stream] Subscribing to cascade ${cascadeId.substring(0, 8)}...`); - - const gidBuf = Buffer.from(cascadeId, 'utf-8'); - // field1=version(varint=1), field2=cascadeId(string) - const proto = Buffer.alloc(2 + 2 + gidBuf.length); - proto[0] = 0x08; proto[1] = 0x01; - proto[2] = 0x12; proto[3] = gidBuf.length; - gidBuf.copy(proto, 4); - - // ConnectRPC frame - const frame = Buffer.alloc(5 + proto.length); - frame[0] = 0x00; - frame.writeUInt32BE(proto.length, 1); - proto.copy(frame, 5); - - const req = http.request({ - hostname: '127.0.0.1', port: lsPort, - path: '/exa.language_server_pb.LanguageServerService/StreamCascadeReactiveUpdates', - method: 'POST', - headers: { - 'Content-Type': 'application/connect+proto', - 'Connect-Protocol-Version': '1', - 'x-codeium-csrf-token': lsCsrf, - }, - timeout: 30000 - }, (res: any) => { - console.log(`Gravity Bridge: [Stream] Connected! status=${res.statusCode}`); - let totalBytes = 0; - const allChunks: Buffer[] = []; - - res.on('data', (chunk: Buffer) => { - allChunks.push(chunk); - totalBytes += chunk.length; - // Log each chunk as it arrives (real-time streaming) - const text = chunk.toString('utf-8'); - console.log(`Gravity Bridge: [Stream] chunk (${chunk.length}B): ${text.substring(0, 300)}`); - }); - - res.on('end', () => { - const fullBuf = Buffer.concat(allChunks); - const fullText = fullBuf.toString('utf-8'); - console.log(`Gravity Bridge: [Stream] Ended. Total ${totalBytes}B in ${allChunks.length} chunks`); - - // Try to extract readable text from the stream data - // Look for strings in the protobuf data - const readable = fullText.replace(/[\x00-\x1F\x7F-\x9F]/g, ' ').replace(/\s+/g, ' ').trim(); - if (readable.length > 20) { - console.log(`Gravity Bridge: [Stream] Readable: ${readable.substring(0, 1000)}`); + await sdk.cascade.acceptStep(); + vscode.window.showInformationMessage('Gravity Bridge: Step approved'); + } catch (e: any) { + vscode.window.showErrorMessage(`Approve failed: ${e.message}`); } - - // Check for error messages - if (fullText.includes('"error"')) { - console.log(`Gravity Bridge: [Stream] Error in response: ${fullText.substring(0, 500)}`); + }), + vscode.commands.registerCommand('gravityBridge.reject', async () => { + try { + await sdk.cascade.rejectStep(); + vscode.window.showInformationMessage('Gravity Bridge: Step rejected'); + } catch (e: any) { + vscode.window.showErrorMessage(`Reject failed: ${e.message}`); } - }); - }); - req.on('error', (e: any) => console.log(`Gravity Bridge: [Stream] Error: ${e.message}`)); - req.on('timeout', () => { - console.log(`Gravity Bridge: [Stream] Timeout (30s) — closing`); - req.destroy(); - }); - req.write(frame); - req.end(); + }) + ); + } else { + statusBar.text = '$(warning) Bridge (no SDK)'; + console.log('Gravity Bridge: SDK not available, file-based mode only'); } + // Watch commands directory + watchCommandsDir(); - // Start LS bridge after a delay - setTimeout(async () => { - const found = await discoverLS(); - if (found) { - console.log(`Gravity Bridge: [LS] bridge active — polling every 5s`); - // Initialize step counts - await pollConversations(); - // Start polling loop - setInterval(pollConversations, 5000); - } else { - console.log(`Gravity Bridge: [LS] bridge NOT available — AI responses won't relay`); - } - }, 8000); - - - // Chat document change listener — captures AI text responses + // Register basic commands context.subscriptions.push( - vscode.workspace.onDidChangeTextDocument((event) => { - handleChatDocumentChange(event); + 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: any) => ({ + 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 as any).sessionId); + vscode.window.showInformationMessage(`Connected to: ${(pick as any).label}`); + } + } catch (e: any) { + vscode.window.showErrorMessage(`Connect failed: ${e.message}`); + } }) ); - // Register @bridge Chat Participant for history relay - try { - const participant = vscode.chat.createChatParticipant( - 'gravity-bridge.gravity', - bridgeChatHandler - ); - participant.iconPath = new vscode.ThemeIcon('radio-tower'); - context.subscriptions.push(participant); - console.log('Gravity Bridge: @bridge chat participant registered'); - } catch (err) { - console.log('Gravity Bridge: chat participant API not available (OK)'); - } - - // Auto-watch brain/ for new conversations → auto-register - watchBrainForNewSessions(); - - // Auto-start - startBridge(); -} - -function startBridge() { - if (isActive) { - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): already running`); - return; - } + // 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; - statusBar.text = `$(radio-tower) ${projectName}: On`; - statusBar.tooltip = `Gravity Bridge — ${projectName} (Active)`; - statusBar.command = 'gravityBridge.stop'; - - // Watch bridge/response/ for Discord user responses - const responsePath = path.join(bridgePath, 'response'); - const processedFiles = new Set(); // Debounce - try { - watcher = fs.watch(responsePath, { persistent: false }, (eventType, filename) => { - if (filename && filename.endsWith('.json') && !processedFiles.has(filename)) { - processedFiles.add(filename); - setTimeout(() => processedFiles.delete(filename), 2000); - handleResponse(path.join(responsePath, filename)); - } - }); - console.log('Gravity Bridge: watching response directory'); - } catch (err) { - console.error('Gravity Bridge: failed to watch response dir', err); - } - - // Watch for commands (user text input from Discord) - const commandsPath = path.join(bridgePath, 'commands'); - try { - commandsWatcher = fs.watch(commandsPath, { persistent: false }, (eventType, filename) => { - if (filename && filename.endsWith('.json') && !processedFiles.has(filename)) { - processedFiles.add(filename); - setTimeout(() => processedFiles.delete(filename), 2000); - handleCommand(path.join(commandsPath, filename)); - } - }); - console.log('Gravity Bridge: watching commands directory'); - } catch (err) { - console.error('Gravity Bridge: failed to watch commands dir', err); - } - - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): Started`); - console.log(`Gravity Bridge: started for project "${projectName}", bridge: ${bridgePath}`); } -function stopBridge() { - if (!isActive) { return; } - - isActive = false; - statusBar.text = `$(radio-tower) ${projectName}: Off`; - statusBar.tooltip = `Gravity Bridge — ${projectName}`; - statusBar.command = 'gravityBridge.start'; - - if (watcher) { watcher.close(); watcher = null; } - if (commandsWatcher) { commandsWatcher.close(); commandsWatcher = null; } - - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): Stopped`); -} - -/** - * Handle a response from Discord (approve/reject). - * Only processes responses — no project filtering needed since request_id is unique. - */ -async function handleResponse(filePath: string) { - try { - await new Promise(resolve => setTimeout(resolve, 200)); - - if (!fs.existsSync(filePath)) { return; } - - const content = fs.readFileSync(filePath, 'utf-8'); - const response = JSON.parse(content); - - if (response.approved === undefined) { return; } - - console.log(`Gravity Bridge [${projectName}]: response — approved=${response.approved}`); - - if (response.approved) { - await simulateApproval(); - vscode.window.showInformationMessage(`✅ Approved: ${response.request_id}`); - } else { - await simulateRejection(); - vscode.window.showInformationMessage(`❌ Rejected: ${response.request_id}`); - } - - try { fs.unlinkSync(filePath); } catch (e) { /* ignore */ } - } catch (err) { - console.error('Gravity Bridge: error handling response', err); - } -} - -/** - * Handle a text command from Discord. - * ONLY processes commands matching this project's name. - */ -async function handleCommand(filePath: string) { - try { - await new Promise(resolve => setTimeout(resolve, 200)); - - if (!fs.existsSync(filePath)) { return; } - - const content = fs.readFileSync(filePath, 'utf-8'); - const command = JSON.parse(content); - - if (command.consumed || !command.text) { return; } - - // ★ PROJECT FILTER — only process commands for THIS project - const cmdProject = command.project_name || ''; - if (cmdProject && cmdProject !== projectName) { - console.log(`Gravity Bridge [${projectName}]: skipping command for "${cmdProject}"`); - return; // Not for us — leave file for the correct Extension instance - } - - const text = command.text.trim(); - console.log(`Gravity Bridge [${projectName}]: command — "${text.substring(0, 50)}"`); - - // Special command: !stop — cancel AI work - if (text === '!stop') { - try { - await vscode.commands.executeCommand('workbench.action.chat.stop'); - vscode.window.showWarningMessage(`⏹️ [${projectName}] AI 작업 중지됨`); - } catch { - vscode.window.showErrorMessage('AI 중지 명령 실행 실패'); - } - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - return; - } - - // Special command: auto-approve toggle - if (text === '!auto on' || text === '!auto off') { - const enabled = text === '!auto on'; - await toggleAutoApprove(enabled); - - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - return; - } - - // General text: send directly to Antigravity agent panel - try { - await vscode.commands.executeCommand('antigravity.sendPromptToAgentPanel', command.text); - console.log(`Gravity Bridge: ✅ sent via sendPromptToAgentPanel`); - } catch (e1) { - console.log(`Gravity Bridge: sendPromptToAgentPanel failed: ${e1}`); - // Fallback: try sendChatActionMessage - try { - await vscode.commands.executeCommand('antigravity.sendChatActionMessage', command.text); - console.log(`Gravity Bridge: ✅ sent via sendChatActionMessage`); - } catch (e2) { - console.log(`Gravity Bridge: sendChatActionMessage failed: ${e2}`); - // Last resort: focus panel + clipboard paste - try { - await vscode.commands.executeCommand('antigravity.agentPanel.focus'); - await new Promise(resolve => setTimeout(resolve, 300)); - const oldClip = await vscode.env.clipboard.readText(); - await vscode.env.clipboard.writeText(command.text); - await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); - await vscode.env.clipboard.writeText(oldClip); - console.log('Gravity Bridge: clipboard paste fallback'); - } catch (e3) { - console.error('Gravity Bridge: all methods failed', e3); - } - } - } - - // Always mark as consumed - command.consumed = true; - fs.writeFileSync(filePath, JSON.stringify(command, null, 2), 'utf-8'); - } catch (err) { - console.error('Gravity Bridge: error handling command', err); - } -} - -/** - * Toggle Antigravity's auto-approve settings. - */ -async function toggleAutoApprove(enabled: boolean) { - const config = vscode.workspace.getConfiguration(); - - try { - await config.update('chat.tools.autoApprove', enabled, vscode.ConfigurationTarget.Global); - await config.update('chat.agent.autoApprove', enabled, vscode.ConfigurationTarget.Global); - - if (enabled) { - await config.update('chat.tools.terminal.enableAutoApprove', true, vscode.ConfigurationTarget.Global); - } - await config.update('autoAcceptV2.autoAcceptFileEdits', enabled, vscode.ConfigurationTarget.Global); - - statusBar.text = enabled - ? `$(radio-tower) ${projectName}: Auto ✅` - : `$(radio-tower) ${projectName}: Manual 🔒`; - - const mode = enabled ? '자동 승인 ON 🟢' : '수동 승인 OFF 🔴'; - vscode.window.showInformationMessage(`Gravity Bridge (${projectName}): ${mode}`); - - const statusPath = path.join(bridgePath, 'commands', `auto-status-${Date.now()}.json`); - fs.writeFileSync(statusPath, JSON.stringify({ - id: `auto-status-${Date.now()}`, - project_name: projectName, - text: `[SYSTEM] Auto-approve: ${enabled ? 'ON' : 'OFF'}`, - timestamp: Date.now() / 1000, - consumed: true, - auto_approve: enabled, - }, null, 2), 'utf-8'); - - } catch (err) { - console.error('Gravity Bridge: failed to toggle auto-approve', err); - } -} - -async function simulateApproval() { - try { - await vscode.commands.executeCommand('workbench.action.acceptSelectedCodeAction'); - } catch { - try { - await vscode.commands.executeCommand('type', { text: '\n' }); - } catch { - await vscode.commands.executeCommand('workbench.action.terminal.focus'); - } - } -} - -async function simulateRejection() { - try { - await vscode.commands.executeCommand('workbench.action.closeQuickOpen'); - } catch { - try { - await vscode.commands.executeCommand('cancelSelection'); - } catch { - console.log('Gravity Bridge: rejection sent but no active dialog found'); - } - } -} - -/** - * Manual approve/reject from command palette. - */ -function handleManualAction(approved: boolean) { - const requestId = `manual-${Date.now()}`; - const responsePath = path.join(bridgePath, 'response', `${requestId}.json`); - - const response = { - request_id: requestId, - approved: approved, - user_input: '', - timestamp: Date.now() / 1000, - }; - - fs.writeFileSync(responsePath, JSON.stringify(response, null, 2), 'utf-8'); - - if (approved) { simulateApproval(); } - else { simulateRejection(); } -} - -/** - * Write a pending approval request to bridge/pending/ for Discord bot to pick up. - * Includes project_name for correct channel routing. - */ -export function writePendingApproval( - conversationId: string, - command: string, - description: string -): string { - const requestId = `req-${Date.now()}`; - const pendingPath = path.join(bridgePath, 'pending', `${requestId}.json`); - - const request = { - request_id: requestId, - conversation_id: conversationId, - project_name: projectName, // ★ Project routing - command: command, - description: description, - timestamp: Date.now() / 1000, - status: 'pending', - discord_message_id: 0, - }; - - fs.writeFileSync(pendingPath, JSON.stringify(request, null, 2), 'utf-8'); - sentPendingIds.add(requestId); - - console.log(`Gravity Bridge [${projectName}]: pending approval — ${requestId}`); - return requestId; -} - -/** - * Register a conversation → project mapping in bridge/register/. - * The bot reads these files to route brain events to the correct channel. - */ -function registerConversation(conversationId: string) { - const registerDir = path.join(bridgePath, 'register'); - if (!fs.existsSync(registerDir)) { - fs.mkdirSync(registerDir, { recursive: true }); - } - - const filePath = path.join(registerDir, `${conversationId}.json`); - const data = { - conversation_id: conversationId, - project_name: projectName, - timestamp: Date.now() / 1000, - }; - - fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); - console.log(`Gravity Bridge [${projectName}]: registered ${conversationId.substring(0, 8)}`); -} - -/** - * Read the title (first # heading) from a conversation's task.md or implementation_plan.md. - */ -function getConversationTitle(convDir: string): string { - for (const fname of ['task.md', 'implementation_plan.md']) { - const fpath = path.join(convDir, fname); - if (fs.existsSync(fpath)) { - try { - const lines = fs.readFileSync(fpath, 'utf-8').split('\n').slice(0, 5); - for (const line of lines) { - const match = line.match(/^#\s+(.+)/); - if (match) { return match[1].trim().substring(0, 50); } - } - } catch { /* ignore */ } - } - } - return ''; -} - -/** - * Manual connect: scan brain/ for recent conversations and let user pick. - * Shows task.md titles for readability. Offers auto-connect for new projects. - */ -async function connectSession() { - const brainPath = path.join(os.homedir(), '.gemini', 'antigravity', 'brain'); - if (!fs.existsSync(brainPath)) { - vscode.window.showErrorMessage('Brain 디렉토리를 찾을 수 없습니다.'); - return; - } - - // Get conversation dirs sorted by modification time (newest first) - const dirs = fs.readdirSync(brainPath) - .filter(d => { - const fullPath = path.join(brainPath, d); - return fs.statSync(fullPath).isDirectory() && d.includes('-'); - }) - .map(d => { - const fullPath = path.join(brainPath, d); - return { - name: d, - mtime: fs.statSync(fullPath).mtimeMs, - title: getConversationTitle(fullPath), - }; - }) - .sort((a, b) => b.mtime - a.mtime) - .slice(0, 10); - - // Build QuickPick items - const items: (vscode.QuickPickItem & { convId?: string })[] = []; - - // Always offer auto-connect option first - items.push({ - label: '$(sync) 새 대화 자동 연결', - description: '다음에 시작하는 대화가 자동으로 이 프로젝트에 연결됩니다', - detail: `프로젝트: ${projectName}`, - }); - - // Add conversation items with titles - for (const d of dirs) { - const titleLabel = d.title || '(제목 없음)'; - const timeStr = new Date(d.mtime).toLocaleString(); - items.push({ - label: `$(comment-discussion) ${titleLabel}`, - description: d.name.substring(0, 8), - detail: `${d.name} · ${timeStr}`, - convId: d.name, - } as any); - } - - const selected = await vscode.window.showQuickPick(items, { - placeHolder: `프로젝트 "${projectName}"에 연결할 세션을 선택하세요`, - }); - - if (!selected) { return; } - - if (!('convId' in selected) || !selected.convId) { - // Auto-connect mode - vscode.window.showInformationMessage( - `🔄 ${projectName}: 다음 대화가 자동으로 연결됩니다` - ); - return; - } - - registerConversation(selected.convId); - vscode.window.showInformationMessage( - `✅ ${selected.description} → ${projectName} 연결됨` - ); -} - -/** - * Auto-watch brain/ for new conversation directories → auto-register. - */ -function watchBrainForNewSessions() { - const brainPath = path.join(os.homedir(), '.gemini', 'antigravity', 'brain'); - if (!fs.existsSync(brainPath)) { return; } - - // Track known dirs - const knownDirs = new Set( - fs.readdirSync(brainPath).filter(d => - fs.statSync(path.join(brainPath, d)).isDirectory() - ) - ); - - try { - fs.watch(brainPath, { persistent: false }, (eventType, filename) => { - if (!filename || !filename.includes('-')) { return; } - const fullPath = path.join(brainPath, filename); - - // Check if it's a new directory - if (!knownDirs.has(filename) && fs.existsSync(fullPath) && - fs.statSync(fullPath).isDirectory()) { - knownDirs.add(filename); - registerConversation(filename); - console.log(`Gravity Bridge [${projectName}]: auto-registered new session ${filename.substring(0, 8)}`); - } - }); - console.log(`Gravity Bridge [${projectName}]: watching brain/ for new sessions`); - } catch (err) { - console.error('Gravity Bridge: failed to watch brain dir', err); - } -} - -/** - * Monitor text document changes for chat panel content. - * VS Code chat documents have special URI schemes (vscode-chat-response, etc.). - * We capture significant changes and relay to Discord. - */ -let lastChatContent = ''; -let chatDebounceTimer: NodeJS.Timeout | null = null; - -function handleChatDocumentChange(event: vscode.TextDocumentChangeEvent) { - const doc = event.document; - const scheme = doc.uri.scheme; - - // Log ALL schemes to discover chat-related ones (debug mode) - if (scheme !== 'file' && scheme !== 'git' && scheme !== 'output' && - scheme !== 'vscode-userdata' && scheme !== 'untitled') { - console.log(`Gravity Bridge [${projectName}]: doc change scheme="${scheme}" uri="${doc.uri.toString().substring(0, 80)}"`); - } - - // Capture chat-related documents - // Known chat schemes: vscode-chat-response, vscode-copilot-chat, etc. - const isChatDoc = scheme.includes('chat') || scheme.includes('copilot') || - scheme.includes('notebook') || doc.uri.path.includes('chat'); - - if (!isChatDoc) { return; } - - const content = doc.getText(); - if (!content || content === lastChatContent) { return; } - - // Debounce: wait 2s for content to stabilize (AI streams text) - if (chatDebounceTimer) { clearTimeout(chatDebounceTimer); } - chatDebounceTimer = setTimeout(() => { - const finalContent = doc.getText(); - if (finalContent && finalContent !== lastChatContent && finalContent.length > 20) { - lastChatContent = finalContent; - writeChatSnapshot(finalContent); - } - }, 2000); -} - -/** - * Write a chat content snapshot to bridge for the bot to relay. - */ -function writeChatSnapshot(content: string) { - const snapshotDir = path.join(bridgePath, 'chat_snapshots'); - if (!fs.existsSync(snapshotDir)) { - fs.mkdirSync(snapshotDir, { recursive: true }); - } - - const id = `chat-${Date.now()}`; - const filePath = path.join(snapshotDir, `${id}.json`); - const data = { - id, - project_name: projectName, - content: content.substring(0, 4000), // Limit size - timestamp: Date.now() / 1000, - }; - - fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); - console.log(`Gravity Bridge [${projectName}]: chat snapshot written (${content.length} chars)`); -} - -/** - * @bridge Chat Participant handler. - * Reads conversation history and sends to Discord via bridge. - */ -const bridgeChatHandler: vscode.ChatRequestHandler = async ( - request: vscode.ChatRequest, - context: vscode.ChatContext, - stream: vscode.ChatResponseStream, - token: vscode.CancellationToken -) => { - const command = request.prompt.trim().toLowerCase(); - - if (command === 'stop' || command === '중지') { - // Cancel current AI work - try { - await vscode.commands.executeCommand('workbench.action.chat.stop'); - stream.markdown('⏹️ AI 작업 중지 요청을 보냈습니다.'); - } catch { - stream.markdown('⚠️ 중지 명령을 실행할 수 없습니다.'); - } - return; - } - - // Collect conversation history - const historyLines: string[] = []; - historyLines.push(`# 대화 히스토리 (${projectName})\n`); - - for (const entry of context.history) { - if (entry instanceof vscode.ChatRequestTurn) { - historyLines.push(`## 👤 사용자\n${entry.prompt}\n`); - } else if (entry instanceof vscode.ChatResponseTurn) { - let responseText = ''; - for (const part of entry.response) { - if (part instanceof vscode.ChatResponseMarkdownPart) { - responseText += part.value.value; - } - } - if (responseText) { - historyLines.push(`## 🤖 AI\n${responseText}\n`); - } - } - } - - if (historyLines.length <= 1) { - stream.markdown('대화 히스토리가 비어있습니다. AI와 대화를 먼저 진행한 후 `@bridge`를 호출하세요.'); - return; - } - - // Write to bridge for Discord relay - const fullHistory = historyLines.join('\n'); - const cmdId = `bridge-history-${Date.now()}`; - const cmdPath = path.join(bridgePath, 'commands', `${cmdId}.json`); - - const data = { - id: cmdId, - project_name: projectName, - text: `[HISTORY]\n${fullHistory}`, - timestamp: Date.now() / 1000, - consumed: false, - }; - - fs.writeFileSync(cmdPath, JSON.stringify(data, null, 2), 'utf-8'); - - stream.markdown(`✅ 대화 히스토리 (${context.history.length}개 턴)를 Discord에 전송했습니다.`); - console.log(`Gravity Bridge [${projectName}]: sent ${context.history.length} turns to Discord`); -}; - export function deactivate() { - stopBridge(); + if (sdk) { + try { sdk.monitor.stop(); sdk.dispose(); } catch { } + } }