SuperCharge Claude Code v1.0.0 - Complete Customization Package
Features: - 30+ Custom Skills (cognitive, development, UI/UX, autonomous agents) - RalphLoop autonomous agent integration - Multi-AI consultation (Qwen) - Agent management system with sync capabilities - Custom hooks for session management - MCP servers integration - Plugin marketplace setup - Comprehensive installation script Components: - Skills: always-use-superpowers, ralph, brainstorming, ui-ux-pro-max, etc. - Agents: 100+ agents across engineering, marketing, product, etc. - Hooks: session-start-superpowers, qwen-consult, ralph-auto-trigger - Commands: /brainstorm, /write-plan, /execute-plan - MCP Servers: zai-mcp-server, web-search-prime, web-reader, zread - Binaries: ralphloop wrapper Installation: ./supercharge.sh
This commit is contained in:
214
skills/dev-browser/extension/services/ConnectionManager.ts
Normal file
214
skills/dev-browser/extension/services/ConnectionManager.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* ConnectionManager - Manages WebSocket connection to relay server.
|
||||
*/
|
||||
|
||||
import type { Logger } from "../utils/logger";
|
||||
import type { ExtensionCommandMessage, ExtensionResponseMessage } from "../utils/types";
|
||||
|
||||
const RELAY_URL = "ws://localhost:9222/extension";
|
||||
const RECONNECT_INTERVAL = 3000;
|
||||
|
||||
export interface ConnectionManagerDeps {
|
||||
logger: Logger;
|
||||
onMessage: (message: ExtensionCommandMessage) => Promise<unknown>;
|
||||
onDisconnect: () => void;
|
||||
}
|
||||
|
||||
export class ConnectionManager {
|
||||
private ws: WebSocket | null = null;
|
||||
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
private shouldMaintain = false;
|
||||
private logger: Logger;
|
||||
private onMessage: (message: ExtensionCommandMessage) => Promise<unknown>;
|
||||
private onDisconnect: () => void;
|
||||
|
||||
constructor(deps: ConnectionManagerDeps) {
|
||||
this.logger = deps.logger;
|
||||
this.onMessage = deps.onMessage;
|
||||
this.onDisconnect = deps.onDisconnect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WebSocket is open (may be stale if server crashed).
|
||||
*/
|
||||
isConnected(): boolean {
|
||||
return this.ws?.readyState === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate connection by checking if server is reachable.
|
||||
* More reliable than isConnected() as it detects server crashes.
|
||||
*/
|
||||
async checkConnection(): Promise<boolean> {
|
||||
if (!this.isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify server is actually reachable
|
||||
try {
|
||||
const response = await fetch("http://localhost:9222", {
|
||||
method: "HEAD",
|
||||
signal: AbortSignal.timeout(1000),
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
// Server unreachable - close stale socket
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
this.onDisconnect();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to the relay server.
|
||||
*/
|
||||
send(message: unknown): void {
|
||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||
try {
|
||||
this.ws.send(JSON.stringify(message));
|
||||
} catch (error) {
|
||||
console.debug("Error sending message:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start maintaining connection (auto-reconnect).
|
||||
*/
|
||||
startMaintaining(): void {
|
||||
this.shouldMaintain = true;
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
this.tryConnect().catch(() => {});
|
||||
this.reconnectTimer = setTimeout(() => this.startMaintaining(), RECONNECT_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop connection maintenance.
|
||||
*/
|
||||
stopMaintaining(): void {
|
||||
this.shouldMaintain = false;
|
||||
if (this.reconnectTimer) {
|
||||
clearTimeout(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from relay and stop maintaining connection.
|
||||
*/
|
||||
disconnect(): void {
|
||||
this.stopMaintaining();
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
this.onDisconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure connection is established, waiting if needed.
|
||||
*/
|
||||
async ensureConnected(): Promise<void> {
|
||||
if (this.isConnected()) return;
|
||||
|
||||
await this.tryConnect();
|
||||
|
||||
if (!this.isConnected()) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
await this.tryConnect();
|
||||
}
|
||||
|
||||
if (!this.isConnected()) {
|
||||
throw new Error("Could not connect to relay server");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to connect to relay server once.
|
||||
*/
|
||||
private async tryConnect(): Promise<void> {
|
||||
if (this.isConnected()) return;
|
||||
|
||||
// Check if server is available
|
||||
try {
|
||||
await fetch("http://localhost:9222", { method: "HEAD" });
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug("Connecting to relay server...");
|
||||
const socket = new WebSocket(RELAY_URL);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error("Connection timeout"));
|
||||
}, 5000);
|
||||
|
||||
socket.onopen = () => {
|
||||
clearTimeout(timeout);
|
||||
resolve();
|
||||
};
|
||||
|
||||
socket.onerror = () => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error("WebSocket connection failed"));
|
||||
};
|
||||
|
||||
socket.onclose = (event) => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`WebSocket closed: ${event.reason || event.code}`));
|
||||
};
|
||||
});
|
||||
|
||||
this.ws = socket;
|
||||
this.setupSocketHandlers(socket);
|
||||
this.logger.log("Connected to relay server");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up WebSocket event handlers.
|
||||
*/
|
||||
private setupSocketHandlers(socket: WebSocket): void {
|
||||
socket.onmessage = async (event: MessageEvent) => {
|
||||
let message: ExtensionCommandMessage;
|
||||
try {
|
||||
message = JSON.parse(event.data);
|
||||
} catch (error) {
|
||||
this.logger.debug("Error parsing message:", error);
|
||||
this.send({
|
||||
error: { code: -32700, message: "Parse error" },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const response: ExtensionResponseMessage = { id: message.id };
|
||||
try {
|
||||
response.result = await this.onMessage(message);
|
||||
} catch (error) {
|
||||
this.logger.debug("Error handling command:", error);
|
||||
response.error = (error as Error).message;
|
||||
}
|
||||
this.send(response);
|
||||
};
|
||||
|
||||
socket.onclose = (event: CloseEvent) => {
|
||||
this.logger.debug("Connection closed:", event.code, event.reason);
|
||||
this.ws = null;
|
||||
this.onDisconnect();
|
||||
if (this.shouldMaintain) {
|
||||
this.startMaintaining();
|
||||
}
|
||||
};
|
||||
|
||||
socket.onerror = (event: Event) => {
|
||||
this.logger.debug("WebSocket error:", event);
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user