193 lines
4.9 KiB
JavaScript
193 lines
4.9 KiB
JavaScript
/**
|
|
* Bridge Client — Antigravity Extension Bridge (localhost:9850)와 통신
|
|
*
|
|
* Extension이 설치된 Antigravity에서 제공하는 REST API + WebSocket을 통해
|
|
* 대화 목록, 메시지 전송, 승인/거절 등을 수행합니다.
|
|
*/
|
|
|
|
const http = require('http');
|
|
const WebSocket = require('ws');
|
|
|
|
const BRIDGE_HOST = 'localhost';
|
|
const BRIDGE_PORT = 9850;
|
|
const BRIDGE_BASE = `http://${BRIDGE_HOST}:${BRIDGE_PORT}`;
|
|
|
|
class BridgeClient {
|
|
constructor() {
|
|
this.ws = null;
|
|
this.connected = false;
|
|
this.listeners = new Map();
|
|
this.reconnectTimer = null;
|
|
}
|
|
|
|
/**
|
|
* Bridge 서버 상태 확인
|
|
*/
|
|
async checkHealth() {
|
|
try {
|
|
const data = await this._get('/api/health');
|
|
return { available: true, ...data };
|
|
} catch {
|
|
return { available: false };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 대화 목록 (제목, stepCount, 수정일시)
|
|
*/
|
|
async getSessions() {
|
|
return this._get('/api/sessions');
|
|
}
|
|
|
|
/**
|
|
* 전체 Cascade 데이터 (대화 내용, 스텝, notify_user 등)
|
|
*/
|
|
async getCascades() {
|
|
return this._get('/api/cascades');
|
|
}
|
|
|
|
/**
|
|
* 개별 대화의 전체 스텝/메시지 (GetCascadeTrajectory RPC)
|
|
*/
|
|
async getTrajectory(cascadeId) {
|
|
return this._post('/api/ls/rpc', {
|
|
method: 'GetCascadeTrajectory',
|
|
payload: { cascadeId },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 메시지 전송
|
|
*/
|
|
async sendMessage(message, sessionId) {
|
|
return this._post('/api/send', { message, sessionId });
|
|
}
|
|
|
|
/**
|
|
* 코드 편집 승인
|
|
*/
|
|
async acceptStep() {
|
|
return this._post('/api/accept', {});
|
|
}
|
|
|
|
/**
|
|
* 코드 편집 거절
|
|
*/
|
|
async rejectStep() {
|
|
return this._post('/api/reject', {});
|
|
}
|
|
|
|
/**
|
|
* 터미널 명령 승인
|
|
*/
|
|
async acceptTerminal() {
|
|
return this._post('/api/accept-terminal', {});
|
|
}
|
|
|
|
/**
|
|
* 에이전트 설정 조회
|
|
*/
|
|
async getPreferences() {
|
|
return this._get('/api/preferences');
|
|
}
|
|
|
|
/**
|
|
* WebSocket 실시간 이벤트 연결
|
|
*/
|
|
connectWs(onMessage) {
|
|
if (this.ws) {
|
|
this.ws.close();
|
|
}
|
|
|
|
try {
|
|
this.ws = new WebSocket(`ws://${BRIDGE_HOST}:${BRIDGE_PORT}/ws`);
|
|
} catch (err) {
|
|
console.log(`[Bridge WS] 연결 실패: ${err.message}`);
|
|
this._scheduleReconnect(onMessage);
|
|
return;
|
|
}
|
|
|
|
this.ws.on('open', () => {
|
|
this.connected = true;
|
|
console.log('[Bridge WS] 연결됨');
|
|
});
|
|
|
|
this.ws.on('message', (data) => {
|
|
try {
|
|
const msg = JSON.parse(data.toString());
|
|
onMessage(msg);
|
|
} catch { }
|
|
});
|
|
|
|
this.ws.on('close', () => {
|
|
this.connected = false;
|
|
console.log('[Bridge WS] 연결 해제');
|
|
this._scheduleReconnect(onMessage);
|
|
});
|
|
|
|
this.ws.on('error', () => {
|
|
this.connected = false;
|
|
});
|
|
}
|
|
|
|
_scheduleReconnect(onMessage) {
|
|
if (this.reconnectTimer) return;
|
|
this.reconnectTimer = setTimeout(() => {
|
|
this.reconnectTimer = null;
|
|
console.log('[Bridge WS] 재연결 시도...');
|
|
this.connectWs(onMessage);
|
|
}, 5000);
|
|
}
|
|
|
|
disconnect() {
|
|
if (this.reconnectTimer) {
|
|
clearTimeout(this.reconnectTimer);
|
|
this.reconnectTimer = null;
|
|
}
|
|
if (this.ws) {
|
|
this.ws.close();
|
|
this.ws = null;
|
|
}
|
|
}
|
|
|
|
// --- HTTP 헬퍼 ---
|
|
|
|
_get(path) {
|
|
return new Promise((resolve, reject) => {
|
|
http.get(`${BRIDGE_BASE}${path}`, (res) => {
|
|
let body = '';
|
|
res.on('data', (c) => body += c);
|
|
res.on('end', () => {
|
|
try { resolve(JSON.parse(body)); }
|
|
catch { reject(new Error('Invalid JSON')); }
|
|
});
|
|
}).on('error', reject);
|
|
});
|
|
}
|
|
|
|
_post(path, data) {
|
|
return new Promise((resolve, reject) => {
|
|
const body = JSON.stringify(data);
|
|
const req = http.request(`${BRIDGE_BASE}${path}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Content-Length': Buffer.byteLength(body),
|
|
},
|
|
}, (res) => {
|
|
let resBody = '';
|
|
res.on('data', (c) => resBody += c);
|
|
res.on('end', () => {
|
|
try { resolve(JSON.parse(resBody)); }
|
|
catch { reject(new Error('Invalid JSON')); }
|
|
});
|
|
});
|
|
req.on('error', reject);
|
|
req.write(body);
|
|
req.end();
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = BridgeClient;
|