Skip to content

Commit a7b8ffc

Browse files
author
catlog22
committed
feat(explorer): async task execution, CLI selector fix, WebSocket frame handling
- Task queue now executes tasks in parallel using Promise.all - addFolderToQueue uses selected CLI tool instead of hardcoded 'gemini' - Added CSS styles for queue-cli-selector toolbar - Force refresh notification list after all tasks complete - Fixed WebSocket frame parsing to handle Ping/Pong control frames - Respond to Ping with Pong, ignore other control frames - Eliminates garbled characters in WebSocket logs
1 parent b0bc536 commit a7b8ffc

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

ccw/src/core/server.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -507,9 +507,31 @@ function handleWebSocketUpgrade(req, socket, head) {
507507
// Handle incoming messages
508508
socket.on('data', (buffer) => {
509509
try {
510-
const message = parseWebSocketFrame(buffer);
511-
if (message) {
512-
console.log('[WS] Received:', message);
510+
const frame = parseWebSocketFrame(buffer);
511+
if (!frame) return;
512+
513+
const { opcode, payload } = frame;
514+
515+
switch (opcode) {
516+
case 0x1: // Text frame
517+
if (payload) {
518+
console.log('[WS] Received:', payload);
519+
}
520+
break;
521+
case 0x8: // Close frame
522+
socket.end();
523+
break;
524+
case 0x9: // Ping frame - respond with Pong
525+
const pongFrame = Buffer.alloc(2);
526+
pongFrame[0] = 0x8A; // Pong opcode with FIN bit
527+
pongFrame[1] = 0x00; // No payload
528+
socket.write(pongFrame);
529+
break;
530+
case 0xA: // Pong frame - ignore
531+
break;
532+
default:
533+
// Ignore other frame types (binary, continuation)
534+
break;
513535
}
514536
} catch (e) {
515537
// Ignore parse errors
@@ -529,10 +551,18 @@ function handleWebSocketUpgrade(req, socket, head) {
529551

530552
/**
531553
* Parse WebSocket frame (simplified)
554+
* Returns { opcode, payload } or null
532555
*/
533556
function parseWebSocketFrame(buffer) {
534557
if (buffer.length < 2) return null;
535558

559+
const firstByte = buffer[0];
560+
const opcode = firstByte & 0x0f; // Extract opcode (bits 0-3)
561+
562+
// Opcode types:
563+
// 0x0 = continuation, 0x1 = text, 0x2 = binary
564+
// 0x8 = close, 0x9 = ping, 0xA = pong
565+
536566
const secondByte = buffer[1];
537567
const isMasked = (secondByte & 0x80) !== 0;
538568
let payloadLength = secondByte & 0x7f;
@@ -560,7 +590,7 @@ function parseWebSocketFrame(buffer) {
560590
}
561591
}
562592

563-
return payload.toString('utf8');
593+
return { opcode, payload: payload.toString('utf8') };
564594
}
565595

566596
/**

ccw/src/templates/dashboard-js/views/explorer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,12 @@ async function startTaskQueue() {
836836
'Explorer'
837837
);
838838

839+
// Force refresh notification list to ensure all notifications are displayed
840+
if (typeof renderGlobalNotifications === 'function') {
841+
renderGlobalNotifications();
842+
updateGlobalNotifBadge();
843+
}
844+
839845
// Re-enable start button if there are pending tasks
840846
const hasPending = updateTaskQueue.some(t => t.status === 'pending');
841847
document.getElementById('startQueueBtn').disabled = !hasPending;

0 commit comments

Comments
 (0)