Tighten CLAUDE.dist.md for LLM audience - 15% size reduction Add Repeater_Simple_Input component for managing lists of simple values Add Polymorphic_Field_Helper for JSON-encoded polymorphic form fields Fix incorrect data-sid selector in route-debug help example Fix Form_Utils to use component.$sid() instead of data-sid selector Add response helper functions and use _message as reserved metadata key 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
211 lines
7.4 KiB
JavaScript
211 lines
7.4 KiB
JavaScript
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.DebugClient = void 0;
|
|
const vscode = __importStar(require("vscode"));
|
|
const crypto = __importStar(require("crypto"));
|
|
class DebugClient {
|
|
constructor(formattingProvider) {
|
|
this.ws = null; // WebSocket instance
|
|
this.isConnecting = false;
|
|
this.reconnectTimer = null;
|
|
this.pingTimer = null;
|
|
this.sessionId = null;
|
|
this.serverKey = null;
|
|
this.formattingProvider = formattingProvider;
|
|
this.outputChannel = vscode.window.createOutputChannel('RSPade Debug Proxy');
|
|
this.outputChannel.show();
|
|
this.log('Debug client initialized');
|
|
}
|
|
async start() {
|
|
this.log('Starting debug client...');
|
|
await this.connect();
|
|
}
|
|
async connect() {
|
|
if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) {
|
|
return;
|
|
}
|
|
this.isConnecting = true;
|
|
try {
|
|
// Get authentication from formatting provider
|
|
await this.ensureAuthenticated();
|
|
const serverUrl = await this.formattingProvider.get_server_url();
|
|
if (!serverUrl) {
|
|
throw new Error('No server URL configured');
|
|
}
|
|
// Parse URL and construct WebSocket URL
|
|
const url = new URL(serverUrl);
|
|
const wsProtocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsUrl = `${wsProtocol}//${url.host}/_ide/debug/ws`;
|
|
this.log(`Connecting to WebSocket: ${wsUrl}`);
|
|
// Create WebSocket (standard API doesn't support headers in constructor)
|
|
// We'll send auth after connection
|
|
this.ws = new WebSocket(wsUrl);
|
|
this.setupEventHandlers();
|
|
}
|
|
catch (error) {
|
|
this.log(`Connection failed: ${error.message}`);
|
|
this.isConnecting = false;
|
|
this.scheduleReconnect();
|
|
}
|
|
}
|
|
setupEventHandlers() {
|
|
if (!this.ws)
|
|
return;
|
|
this.ws.onopen = () => {
|
|
this.isConnecting = false;
|
|
this.log('WebSocket connected, sending authentication...');
|
|
// Send authentication as first message
|
|
const signature = crypto
|
|
.createHmac('sha256', this.serverKey)
|
|
.update(this.sessionId)
|
|
.digest('hex');
|
|
this.sendMessage({
|
|
type: 'auth',
|
|
data: {
|
|
sessionId: this.sessionId,
|
|
signature: signature
|
|
}
|
|
});
|
|
// Send initial hello message after auth
|
|
setTimeout(() => {
|
|
this.sendMessage({
|
|
type: 'hello',
|
|
data: { name: 'VS Code Debug Client' }
|
|
});
|
|
// Start ping timer
|
|
this.startPingTimer();
|
|
}, 100);
|
|
};
|
|
this.ws.onmessage = (event) => {
|
|
try {
|
|
const message = JSON.parse(event.data);
|
|
this.handleMessage(message);
|
|
}
|
|
catch (error) {
|
|
this.log(`Failed to parse message: ${error}`);
|
|
}
|
|
};
|
|
this.ws.onclose = () => {
|
|
this.log('WebSocket disconnected');
|
|
this.ws = null;
|
|
this.stopPingTimer();
|
|
this.scheduleReconnect();
|
|
};
|
|
this.ws.onerror = (error) => {
|
|
this.log(`WebSocket error: ${error}`);
|
|
};
|
|
}
|
|
handleMessage(message) {
|
|
this.log(`Received: ${message.type}`, message.data);
|
|
switch (message.type) {
|
|
case 'welcome':
|
|
this.log('✅ Authentication successful! Connected to debug proxy');
|
|
this.log(`Session ID: ${message.data?.sessionId}`);
|
|
break;
|
|
case 'pong':
|
|
this.log(`PONG received! Server responded to ping`);
|
|
break;
|
|
case 'hello_response':
|
|
this.log(`Server says: ${message.data?.message}`);
|
|
break;
|
|
case 'error':
|
|
this.log(`❌ Error: ${message.data?.message}`);
|
|
break;
|
|
default:
|
|
this.log(`Unknown message type: ${message.type}`);
|
|
}
|
|
}
|
|
sendMessage(message) {
|
|
if (this.ws?.readyState === 1) { // 1 = OPEN in standard WebSocket API
|
|
this.ws.send(JSON.stringify(message));
|
|
this.log(`Sent: ${message.type}`, message.data);
|
|
}
|
|
}
|
|
startPingTimer() {
|
|
this.stopPingTimer();
|
|
// Send ping every 5 seconds
|
|
this.pingTimer = setInterval(() => {
|
|
this.sendMessage({
|
|
type: 'ping',
|
|
data: { timestamp: Date.now() }
|
|
});
|
|
this.log('PING sent to server');
|
|
}, 5000);
|
|
}
|
|
stopPingTimer() {
|
|
if (this.pingTimer) {
|
|
clearInterval(this.pingTimer);
|
|
this.pingTimer = null;
|
|
}
|
|
}
|
|
scheduleReconnect() {
|
|
if (this.reconnectTimer) {
|
|
return;
|
|
}
|
|
this.log('Scheduling reconnection in 5 seconds...');
|
|
this.reconnectTimer = setTimeout(() => {
|
|
this.reconnectTimer = null;
|
|
this.connect();
|
|
}, 5000);
|
|
}
|
|
async ensureAuthenticated() {
|
|
// Get auth data from formatting provider
|
|
const authData = await this.formattingProvider.ensure_auth();
|
|
if (!authData) {
|
|
throw new Error('Failed to authenticate');
|
|
}
|
|
// Extract session ID and server key
|
|
this.sessionId = authData.session_id;
|
|
this.serverKey = authData.server_key;
|
|
if (!this.sessionId || !this.serverKey) {
|
|
throw new Error('Invalid auth data');
|
|
}
|
|
}
|
|
log(message, data) {
|
|
const timestamp = new Date().toISOString();
|
|
const logMessage = `[${timestamp}] ${message}`;
|
|
if (data) {
|
|
this.outputChannel.appendLine(`${logMessage}\n${JSON.stringify(data, null, 2)}`);
|
|
}
|
|
else {
|
|
this.outputChannel.appendLine(logMessage);
|
|
}
|
|
}
|
|
dispose() {
|
|
this.stopPingTimer();
|
|
if (this.reconnectTimer) {
|
|
clearTimeout(this.reconnectTimer);
|
|
this.reconnectTimer = null;
|
|
}
|
|
if (this.ws) {
|
|
this.ws.close();
|
|
this.ws = null;
|
|
}
|
|
this.outputChannel.dispose();
|
|
}
|
|
}
|
|
exports.DebugClient = DebugClient;
|
|
//# sourceMappingURL=debug_client.js.map
|