fix(bridge): remove SDK EventMonitor to stop ERR_CONNECTION_REFUSED spam

EventMonitor was dual-polling GetCascadeTrajectorySteps every 2s via rawRPC,
which has a 775-step hard limit and generates connection errors on port change.

Changes:
- Remove entire SDK EventMonitor (onStepCountChanged, onNewConversation, etc.)
- Keep only GetAllCascadeTrajectories POLL at 5s interval
- Remove all sdk.monitor.stop() calls
- Unleash ERR_CONNECTION_REFUSED (127.0.0.1:1080) is Antigravity's own issue
This commit is contained in:
2026-03-08 07:51:50 +09:00
parent 854f33b816
commit f6ae9c87a5
3 changed files with 27 additions and 404 deletions

View File

@@ -220,206 +220,11 @@ function writeRegistration(sessionId: string) {
function setupMonitor() {
if (!sdk) { return; }
// Step count changed → fetch new steps via GetCascadeTrajectorySteps
sdk.monitor.onStepCountChanged(async (e: any) => {
console.log(`Gravity Bridge: [SDK] step changed: "${e.title}" step ${e.newCount} (+${e.delta})`);
// Auto-register session with Bot on first step event
writeRegistration(e.sessionId);
// ── ONE-TIME FULL STEP TYPE DUMP ──
if (!lastSeenStep.has(e.sessionId)) {
try {
const fullData = await sdk.ls.rawRPC('GetCascadeTrajectorySteps', {
cascadeId: e.sessionId
});
if (fullData && Array.isArray(fullData.steps)) {
const typeCounts = new Map<string, { count: number, statuses: Set<string>, keys: Set<string>, sample: any }>();
for (const step of fullData.steps) {
const t = (step.type || '').replace('CORTEX_STEP_TYPE_', '');
const s = (step.status || '').replace('CORTEX_STEP_STATUS_', '');
const dataKeys = Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k));
if (!typeCounts.has(t)) {
typeCounts.set(t, { count: 0, statuses: new Set(), keys: new Set(), sample: step });
}
const entry = typeCounts.get(t)!;
entry.count++;
entry.statuses.add(s);
for (const k of dataKeys) { entry.keys.add(k); }
}
console.log(`Gravity Bridge: ══════════════════════════════════════`);
console.log(`Gravity Bridge: FULL STEP TYPE MAP (${fullData.steps.length} total steps)`);
console.log(`Gravity Bridge: ══════════════════════════════════════`);
for (const [type, info] of typeCounts.entries()) {
console.log(`Gravity Bridge: [TYPE] ${type} ×${info.count} statuses=[${[...info.statuses].join(',')}] keys=[${[...info.keys].join(',')}]`);
// Dump ONE sample of each type
const s = info.sample;
const dataKeys = Object.keys(s).filter(k => !['type', 'status', 'metadata'].includes(k));
for (const k of dataKeys) {
const v = s[k];
const vStr = typeof v === 'object' ? JSON.stringify(v).substring(0, 150) : String(v).substring(0, 150);
console.log(`Gravity Bridge: .${k} (${typeof v}): ${vStr}`);
}
}
console.log(`Gravity Bridge: ══════════════════════════════════════`);
}
} catch (e: any) {
console.log(`Gravity Bridge: full dump error: ${e.message}`);
}
}
try {
// IMPORTANT: Only fetch NEW steps, never re-fetch history
const fromStep = Math.max(
lastSeenStep.get(e.sessionId) ?? e.newCount - e.delta,
e.newCount - e.delta
);
const stepsData = await sdk.ls.rawRPC('GetCascadeTrajectorySteps', {
cascadeId: e.sessionId, startStepIndex: fromStep
});
lastSeenStep.set(e.sessionId, e.newCount);
if (stepsData && Array.isArray(stepsData.steps)) {
// API may ignore startStepIndex — only process the last e.delta steps
const allSteps = stepsData.steps;
const newSteps = allSteps.slice(-e.delta);
console.log(`Gravity Bridge: [SDK] processing ${newSteps.length} of ${allSteps.length} steps`);
let lastPlannerText = '';
for (const step of newSteps) {
const sType = step.type || '';
const sStatus = step.status || '';
const shortType = sType.replace('CORTEX_STEP_TYPE_', '');
const shortStatus = sStatus.replace('CORTEX_STEP_STATUS_', '');
// ── DIAGNOSTIC: log ALL step types (minimal) ──
console.log(`Gravity Bridge: [STEP] ${shortType} ${shortStatus}`);
// ══════════════════════════════════════════════
// ANY WAITING step → Pending Approval to Discord
// ══════════════════════════════════════════════
if (sStatus.includes('WAITING')) {
let description = '';
let command = '';
if (sType.includes('RUN_COMMAND')) {
const rc = step.runCommand || {};
command = rc.commandLine || rc.proposedCommandLine || '';
description = `💻 **명령 실행 요청**\n\`\`\`\n${command}\n\`\`\`\ncwd: ${rc.cwd || ''}`;
} else if (sType.includes('EDIT_FILE') || sType.includes('CODE_EDIT') || sType.includes('CODE_ACTION') || sType.includes('WRITE_FILE') || sType.includes('FILE_EDIT')) {
// File edit/write/code action
const edit = step.codeEdit || step.editFile || step.writeFile || step.codeAction || {};
const filePath = edit.filePath || edit.targetFile || edit.path || '';
const desc = edit.description || edit.instruction || '';
command = `📝 파일 수정: ${filePath}`;
description = `📝 **파일 변경 확인**\n파일: \`${filePath}\`\n${desc ? `설명: ${desc}` : ''}`;
// Full dump for diagnostic
console.log(`Gravity Bridge: [STEP-DETAIL] ${shortType} WAITING keys=${JSON.stringify(Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k)))}`);
for (const k of Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k))) {
const v = step[k];
console.log(`Gravity Bridge: [STEP-DETAIL] .${k} = ${typeof v === 'object' ? JSON.stringify(v).substring(0, 200) : String(v).substring(0, 200)}`);
}
} else if (sType.includes('FILE_ACCESS') || sType.includes('READ_FILE') || sType.includes('FILE_READ')) {
// File access permission
const fa = step.fileAccess || step.readFile || step.fileRead || {};
const filePath = fa.filePath || fa.path || '';
command = `📖 파일 접근: ${filePath}`;
description = `📖 **파일 접근 권한 요청**\n파일: \`${filePath}\``;
console.log(`Gravity Bridge: [STEP-DETAIL] ${shortType} WAITING keys=${JSON.stringify(Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k)))}`);
for (const k of Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k))) {
const v = step[k];
console.log(`Gravity Bridge: [STEP-DETAIL] .${k} = ${typeof v === 'object' ? JSON.stringify(v).substring(0, 200) : String(v).substring(0, 200)}`);
}
} else {
// Unknown WAITING step — still relay it with full diagnostic
const stepKeys = Object.keys(step).filter(k => !['type', 'status', 'metadata'].includes(k));
command = `${shortType}`;
description = `⏳ **대기 중: ${shortType}**\nkeys: ${stepKeys.join(', ')}`;
console.log(`Gravity Bridge: [STEP-DETAIL] UNKNOWN WAITING: ${shortType} keys=${JSON.stringify(stepKeys)}`);
for (const k of stepKeys) {
const v = step[k];
console.log(`Gravity Bridge: [STEP-DETAIL] .${k} = ${typeof v === 'object' ? JSON.stringify(v).substring(0, 200) : String(v).substring(0, 200)}`);
}
}
writePendingApproval({
conversation_id: e.sessionId,
command: command,
description: `${description}\n\n🏷 ${e.title}`,
});
console.log(`Gravity Bridge: [SDK] ⏳ pending ${shortType}: "${command.substring(0, 80)}"`);
continue;
}
// ══════════════════════════════════════════════
// PLANNER_RESPONSE → AI text relay (COMPLETED/DONE)
// ══════════════════════════════════════════════
if (sType.includes('PLANNER_RESPONSE')) {
if (!sStatus.includes('COMPLETED') && !sStatus.includes('DONE')) {
continue;
}
const pr = step.plannerResponse;
const responseText = pr?.modifiedResponse || pr?.response || '';
if (responseText && typeof responseText === 'string' && responseText.length > 0) {
lastPlannerText = responseText;
console.log(`Gravity Bridge: [SDK] 📝 planner response found (${responseText.length} chars)`);
}
continue;
}
// ══════════════════════════════════════════════
// NOTIFY_USER → also relay as chat snapshot
// ══════════════════════════════════════════════
if (sType.includes('NOTIFY_USER') && (sStatus.includes('COMPLETED') || sStatus.includes('DONE'))) {
const nu = step.notifyUser;
const content = nu?.notificationContent || '';
if (content && content.length > 0) {
// Write NOTIFY_USER as snapshot too
writeChatSnapshot(`📣 **알림**\n\n${content}`);
console.log(`Gravity Bridge: [SDK] 📣 NOTIFY_USER relayed (${content.length} chars)`);
}
continue;
}
}
// Write the LAST planner response as snapshot (with dedup)
if (lastPlannerText && lastPlannerText !== lastSnapshotText.get(e.sessionId)) {
lastSnapshotText.set(e.sessionId, lastPlannerText);
writeChatSnapshot(`🤖 **${e.title}**\n\n${lastPlannerText}`);
console.log(`Gravity Bridge: [SDK] 💬 snapshot written (${lastPlannerText.length} chars)`);
}
return;
}
} catch (err: any) {
console.log(`Gravity Bridge: [SDK] steps error: ${err.message}`);
}
// Fallback
lastSeenStep.set(e.sessionId, e.newCount);
});
// New conversation started
sdk.monitor.onNewConversation((e: any) => {
console.log(`Gravity Bridge: [SDK] new conversation: ${e.title}`);
writeRegistration(e.sessionId || e.id || '');
writeChatSnapshot(`🚀 **${e.title}** — 새 대화 시작`);
});
// Active session changed
sdk.monitor.onActiveSessionChanged((e: any) => {
console.log(`Gravity Bridge: [SDK] active session: "${e.title}" (${e.sessionId?.substring(0, 8)})`);
writeRegistration(e.sessionId || e.id || '');
});
// 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)');
// NOTE: SDK EventMonitor DISABLED to prevent ERR_CONNECTION_REFUSED spam.
// Root cause: EventMonitor polls GetCascadeTrajectorySteps every 2s via rawRPC,
// which has a 775-step hard limit and generates connection errors.
// ALL relay is now handled by the GetAllCascadeTrajectories POLL below.
console.log('Gravity Bridge: SDK monitor DISABLED (using GetAllCascadeTrajectories POLL instead)');
// ══════════════════════════════════════════════════════════════════════
// PRIMARY RELAY: GetAllCascadeTrajectories (THE CORRECT API!)
@@ -564,7 +369,7 @@ function setupMonitor() {
console.log(`Gravity Bridge: [POLL#${pollCount}] error: ${e.message}`);
}
}
}, 3000);
}, 5000);
}
// ─── Response Watcher (Discord approval → Antigravity RPC) ───
@@ -759,9 +564,9 @@ export async function activate(context: vscode.ExtensionContext) {
const sdkReady = await initSDK(context);
if (sdkReady) {
setupMonitor();
statusBar.text = '$(check) Bridge SDK';
statusBar.tooltip = `Gravity Bridge: ${projectName} (SDK active)`;
setupMonitor(); // Now just logs that monitor is disabled
statusBar.text = '$(check) Bridge';
statusBar.tooltip = `Gravity Bridge: ${projectName} (POLL active)`;
// Register SDK-powered commands
context.subscriptions.push(
@@ -801,7 +606,7 @@ export async function activate(context: vscode.ExtensionContext) {
}),
vscode.commands.registerCommand('gravityBridge.stop', () => {
isActive = false;
if (sdk) { sdk.monitor.stop(); }
// SDK monitor is disabled, no need to stop
statusBar.text = '$(circle-slash) Bridge OFF';
vscode.window.showInformationMessage('Gravity Bridge stopped');
}),
@@ -833,7 +638,7 @@ export async function activate(context: vscode.ExtensionContext) {
// Cleanup
context.subscriptions.push({
dispose: () => {
if (sdk) { sdk.monitor.stop(); sdk.dispose(); }
if (sdk) { try { sdk.dispose(); } catch { } }
if (watcher) { watcher.close(); }
if (commandsWatcher) { commandsWatcher.close(); }
}
@@ -845,6 +650,6 @@ export async function activate(context: vscode.ExtensionContext) {
export function deactivate() {
if (sdk) {
try { sdk.monitor.stop(); sdk.dispose(); } catch { }
try { sdk.dispose(); } catch { }
}
}