fix(bridge): resolve websocket zombie connection and bounding memory leaks

This commit is contained in:
Variet Worker
2026-03-23 21:11:52 +09:00
parent e21f71baf8
commit ecebec3906
10 changed files with 110 additions and 25 deletions

View File

@@ -44,6 +44,7 @@ var __importStar = (this && this.__importStar) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.fixLSConnection = fixLSConnection;
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
@@ -251,18 +252,24 @@ async function initSDK(context) {
* found (wrong workspace).
*/
async function fixLSConnection() {
if (!sdk?.ls)
return;
if (!sdk?.ls) {
logToFile('[LS-FIX] skipped: sdk.ls not available');
return false;
}
try {
const folders = vscode.workspace.workspaceFolders;
if (!folders || folders.length === 0)
return;
if (!folders || folders.length === 0) {
logToFile('[LS-FIX] skipped: no workspace folders');
return false;
}
// Generate the workspace hint the same way SDK does, but we'll match case-insensitively
const folder = folders[0].uri.fsPath;
const parts = folder.replace(/\\/g, '/').split('/');
const hint = parts.slice(-2).join('_').replace(/[-.\s]/g, '_').toLowerCase();
if (!hint)
return;
if (!hint) {
logToFile('[LS-FIX] skipped: empty hint');
return false;
}
// Find all language_server processes with csrf_token
const { exec } = cp;
const { promisify } = require('util');
@@ -274,12 +281,18 @@ async function fixLSConnection() {
const result = await execAsync(`powershell.exe -NoProfile -EncodedCommand ${encoded}`, { encoding: 'utf8', timeout: 15000, windowsHide: true });
output = result.stdout;
}
catch {
return; // Can't discover processes — leave SDK's choice
catch (psErr) {
logToFile(`[LS-FIX] skipped: PowerShell failed — ${psErr.message?.substring(0, 100)}`);
return false;
}
const lines = output.split('\n').filter((l) => l.trim().length > 0);
if (lines.length <= 1)
return; // Only one LS — no ambiguity
if (lines.length === 0) {
logToFile('[LS-FIX] skipped: no LS processes found');
return false;
}
// NOTE: Do NOT skip on single LS — SDK may have fallen back to wrong LS
// due to case-sensitive hint mismatch, even when only one process exists.
logToFile(`[LS-FIX] found ${lines.length} LS process(es), hint="${hint}"`);
// Find the line whose workspace_id matches our workspace (case-insensitive)
let matchedLine = null;
for (const line of lines) {
@@ -296,7 +309,7 @@ async function fixLSConnection() {
}
if (!matchedLine) {
logToFile(`[LS-FIX] No LS process matched hint="${hint}" (${lines.length} processes)`);
return;
return false;
}
// Extract port and csrf_token from matched line
const csrfMatch = matchedLine.match(/--csrf_token[= ](\S+)/);
@@ -304,7 +317,7 @@ async function fixLSConnection() {
const pidMatch = matchedLine.split('|')[0]?.trim();
if (!csrfMatch || !extPortMatch) {
logToFile(`[LS-FIX] Matched LS but missing csrf/port args`);
return;
return false;
}
const csrfToken = csrfMatch[1];
const extPort = parseInt(extPortMatch[1], 10);
@@ -312,7 +325,7 @@ async function fixLSConnection() {
// Check if SDK already connected to this LS
if (sdk.ls.port === extPort) {
logToFile(`[LS-FIX] SDK already on correct LS port=${extPort}`);
return;
return false;
}
// Find ConnectRPC port via netstat (same as SDK logic)
let netstatOutput;
@@ -325,7 +338,7 @@ async function fixLSConnection() {
logToFile(`[LS-FIX] netstat failed, using ext_port=${extPort} for PID=${pid}`);
sdk.ls.setConnection(extPort, csrfToken, false);
logToFile(`[LS-FIX] ✅ Reconnected to correct LS: port=${extPort} hint="${hint}" PID=${pid}`);
return;
return true;
}
const portMatches = netstatOutput.matchAll(/127\.0\.0\.1:(\d+)/g);
const ports = [];
@@ -358,7 +371,7 @@ async function fixLSConnection() {
if (ok) {
sdk.ls.setConnection(port, csrfToken, useTls);
logToFile(`[LS-FIX] ✅ Reconnected to correct LS: port=${port} ${proto} hint="${hint}" PID=${pid}`);
return;
return true;
}
}
catch { /* try next */ }
@@ -367,9 +380,11 @@ async function fixLSConnection() {
// Last resort: use extension_server_port
sdk.ls.setConnection(extPort, csrfToken, false);
logToFile(`[LS-FIX] ✅ Reconnected via ext_port=${extPort} hint="${hint}" PID=${pid}`);
return true;
}
catch (err) {
logToFile(`[LS-FIX] error: ${err.message}`);
return false;
}
}
// ─── Approval Observer + Product.json Checksums extracted to ./html-patcher.ts ───
@@ -515,6 +530,7 @@ async function activate(context) {
recentDiscordSentTexts,
writeChatSnapshot,
writeChatSnapshotWithFiles,
fixLSConnection,
});
// Start HTTP bridge with live step-probe state (prevents stale primitive bug)
const httpBridgeCtx = {

File diff suppressed because one or more lines are too long