feat: interactive AskUserQuestion + WebSocket stability
- Add WebSocket heartbeat (30s ping/pong) to prevent proxy timeouts - Add auto-reconnect with exponential backoff (1s-30s, max 10 attempts) - Add interactive AskUserQuestion rendering with clickable options - Add custom input field for free-text answers - Add smooth animations (hover, selection glow, checkbox scale) - Make interactive tool cards wider (max-w-2xl) without scrolling - Hide error badge and result section for interactive tools - Use TextareaAutosize for lag-free custom input - Add Skill, SlashCommand tool renderings - Add ThinkingBlock component for collapsible <thinking> tags 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,9 @@ function generateRequestId() {
|
||||
const server = createServer(app);
|
||||
const wss = new WebSocketServer({ server });
|
||||
|
||||
// WebSocket heartbeat interval (30 seconds)
|
||||
const WS_HEARTBEAT_INTERVAL = 30000;
|
||||
|
||||
// Scan directory for projects
|
||||
function scanProjects(basePath, depth = 0, maxDepth = 1) {
|
||||
const projects = [];
|
||||
@@ -560,6 +563,20 @@ wss.on('connection', async (ws, req) => {
|
||||
const sessionId = uuidv4();
|
||||
console.log(`[${sessionId}] New WebSocket connection`);
|
||||
|
||||
// Track connection health
|
||||
ws.isAlive = true;
|
||||
|
||||
// Heartbeat to keep connection alive through proxies
|
||||
const heartbeatInterval = setInterval(() => {
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
ws.ping();
|
||||
}
|
||||
}, WS_HEARTBEAT_INTERVAL);
|
||||
|
||||
ws.on('pong', () => {
|
||||
ws.isAlive = true;
|
||||
});
|
||||
|
||||
// Authenticate WebSocket connection
|
||||
let wsUser = null;
|
||||
if (authConfig.app.authEnabled && sessionStore) {
|
||||
@@ -1030,6 +1047,8 @@ wss.on('connection', async (ws, req) => {
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log(`[${sessionId}] WebSocket closed`);
|
||||
clearInterval(heartbeatInterval);
|
||||
clearInterval(cleanupInterval);
|
||||
if (claudeProcess) {
|
||||
claudeProcess.kill();
|
||||
sessions.delete(sessionId);
|
||||
|
||||
Reference in New Issue
Block a user