From bc2fca0da4af107622199313993e27b49d2295d2 Mon Sep 17 00:00:00 2001 From: CD Date: Sun, 8 Mar 2026 00:38:45 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20complete=20SDK=20rewrite=20=E2=80=94=20?= =?UTF-8?q?antigravity-sdk=20v1.6.0=20integration=20(1155=E2=86=92280=20li?= =?UTF-8?q?nes)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extension/gravity-bridge-0.2.0.vsix | Bin 33752 -> 12502 bytes extension/out/extension.js | 1268 +++++------------------- extension/out/extension.js.map | 2 +- extension/src/extension.ts | 1381 ++++++--------------------- 4 files changed, 551 insertions(+), 2100 deletions(-) diff --git a/extension/gravity-bridge-0.2.0.vsix b/extension/gravity-bridge-0.2.0.vsix index b4265f73440e21f4a773c3433f6fecf5b9bf0cb7..91ddf873756cb0540f7e367c63847d19af852a10 100644 GIT binary patch delta 10180 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 Taqo24ab1kaP)k1l8SwuA#?U(e 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 { } + } }