mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
fix: Operation Lightspeed review fixes — padding, dead code, tablet WebGL
- Add SSE padding to backpressure drain write for tunnel clients - Remove dead SessionTerminal from broadcast padding check - Trim whitespace in SSE session filter query params - Remove unused _bufferLazyTerminalData scaffolding code - Skip WebGL on tablets too, not just phones (canvas fallback) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -624,8 +624,8 @@ class CodemanApp {
|
||||
// oversized terminal.write() calls that triggered the stalls.
|
||||
// Disable with ?nowebgl URL param if GPU issues return.
|
||||
this._webglAddon = null;
|
||||
const isMobile = MobileDetection.getDeviceType() === 'mobile';
|
||||
if (!isMobile && !new URLSearchParams(location.search).has('nowebgl') && typeof WebglAddon !== 'undefined') {
|
||||
const skipWebGL = MobileDetection.getDeviceType() !== 'desktop';
|
||||
if (!skipWebGL && !new URLSearchParams(location.search).has('nowebgl') && typeof WebglAddon !== 'undefined') {
|
||||
try {
|
||||
this._webglAddon = new WebglAddon.WebglAddon();
|
||||
this._webglAddon.onContextLoss(() => {
|
||||
@@ -10157,7 +10157,6 @@ class CodemanApp {
|
||||
windowEntry._lazyTerminal = true;
|
||||
windowEntry._lazyPaneTarget = paneData.paneTarget;
|
||||
windowEntry._lazySessionId = paneData.sessionId;
|
||||
windowEntry._lazyBuffer = '';
|
||||
}
|
||||
} else {
|
||||
this.initTeammateTerminal(windowId, paneData, win);
|
||||
|
||||
@@ -471,13 +471,9 @@ Object.assign(CodemanApp.prototype, {
|
||||
// restore → _restoreTeammateTerminalFromLazy() → re-creates Terminal
|
||||
// create (hidden/minimized) → skip initTeammateTerminal, set _lazyTerminal
|
||||
//
|
||||
// The pane buffer is always re-fetched from the API on restore, so no
|
||||
// client-side buffer accumulation is needed (the tmux pane is the source
|
||||
// of truth). Regular (non-teammate) subagent windows use activity HTML
|
||||
// and are unaffected by this optimization.
|
||||
|
||||
/** Max bytes to buffer for a minimized teammate terminal (256KB). */
|
||||
_LAZY_TERMINAL_BUFFER_CAP: 256 * 1024,
|
||||
// The tmux pane buffer is re-fetched from the API on restore. Regular
|
||||
// (non-teammate) subagent windows use activity HTML and are unaffected
|
||||
// by this optimization.
|
||||
|
||||
/**
|
||||
* Dispose a teammate terminal when its window is minimized.
|
||||
@@ -495,8 +491,6 @@ Object.assign(CodemanApp.prototype, {
|
||||
windowData._lazyTerminal = true;
|
||||
windowData._lazyPaneTarget = termData.paneTarget;
|
||||
windowData._lazySessionId = termData.sessionId;
|
||||
// Buffer for any data that arrives while minimized (from pendingData or future writes)
|
||||
windowData._lazyBuffer = '';
|
||||
}
|
||||
|
||||
// Dispose the resize observer
|
||||
@@ -532,7 +526,6 @@ Object.assign(CodemanApp.prototype, {
|
||||
windowData._lazyTerminal = false;
|
||||
windowData._lazyPaneTarget = null;
|
||||
windowData._lazySessionId = null;
|
||||
windowData._lazyBuffer = null;
|
||||
|
||||
if (!paneTarget || !sessionId) return;
|
||||
|
||||
@@ -541,29 +534,6 @@ Object.assign(CodemanApp.prototype, {
|
||||
this.initTeammateTerminal(agentId, paneInfo, windowData.element);
|
||||
},
|
||||
|
||||
/**
|
||||
* Append terminal data to a minimized teammate terminal's lazy buffer.
|
||||
* Called when SSE data arrives for a minimized window. Caps at _LAZY_TERMINAL_BUFFER_CAP.
|
||||
* Returns true if the data was buffered, false if the window is not in lazy mode.
|
||||
*/
|
||||
_bufferLazyTerminalData(agentId, data) {
|
||||
const windowData = this.subagentWindows.get(agentId);
|
||||
if (!windowData || !windowData._lazyTerminal) return false;
|
||||
|
||||
if (windowData._lazyBuffer === null || windowData._lazyBuffer === undefined) {
|
||||
windowData._lazyBuffer = '';
|
||||
}
|
||||
|
||||
// Append data, capping total size
|
||||
windowData._lazyBuffer += data;
|
||||
if (windowData._lazyBuffer.length > this._LAZY_TERMINAL_BUFFER_CAP) {
|
||||
// Keep only the tail to stay under cap
|
||||
windowData._lazyBuffer = windowData._lazyBuffer.slice(-this._LAZY_TERMINAL_BUFFER_CAP);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Subagent Floating Windows
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
@@ -809,7 +779,6 @@ Object.assign(CodemanApp.prototype, {
|
||||
windowEntry._lazyTerminal = true;
|
||||
windowEntry._lazyPaneTarget = paneInfo.paneTarget;
|
||||
windowEntry._lazySessionId = paneInfo.sessionId;
|
||||
windowEntry._lazyBuffer = '';
|
||||
}
|
||||
} else {
|
||||
this.initTeammateTerminal(agentId, paneInfo, win);
|
||||
|
||||
+10
-9
@@ -601,7 +601,10 @@ export class WebServer extends EventEmitter {
|
||||
const query = req.query as { sessions?: string };
|
||||
let sessionFilter: Set<string> | null = null;
|
||||
if (query.sessions) {
|
||||
const ids = query.sessions.split(',').filter(Boolean);
|
||||
const ids = query.sessions
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
if (ids.length > 0) {
|
||||
sessionFilter = new Set(ids);
|
||||
}
|
||||
@@ -1963,7 +1966,8 @@ export class WebServer extends EventEmitter {
|
||||
// Client may have missed terminal data during backpressure.
|
||||
// Tell it to reload the active session's buffer to recover.
|
||||
try {
|
||||
reply.raw.write(`event: ${SseEvent.SessionNeedsRefresh}\ndata: {}\n\n`);
|
||||
const drainPadding = this._isTunnelActive ? SSE_PADDING : '';
|
||||
reply.raw.write(`event: ${SseEvent.SessionNeedsRefresh}\ndata: {}\n\n${drainPadding}`);
|
||||
} catch {
|
||||
/* client gone */
|
||||
}
|
||||
@@ -1990,13 +1994,10 @@ export class WebServer extends EventEmitter {
|
||||
}
|
||||
// Performance optimization: serialize JSON once for all clients.
|
||||
// Only append Cloudflare tunnel padding for latency-sensitive events —
|
||||
// high-frequency terminal data and recovery events need immediate proxy flush,
|
||||
// but low-frequency metadata events (session:created, ralph:*, respawn:*, etc.)
|
||||
// are small and infrequent enough that proxy buffering doesn't matter.
|
||||
// Note: session:terminal bypasses broadcast() via flushSessionTerminalBatch(),
|
||||
// but is included here for completeness in case the path changes.
|
||||
const needsPadding =
|
||||
this._isTunnelActive && (event === SseEvent.SessionTerminal || event === SseEvent.SessionNeedsRefresh);
|
||||
// Recovery events need immediate proxy flush; low-frequency metadata events
|
||||
// (session:created, ralph:*, respawn:*, etc.) don't need padding.
|
||||
// Note: session:terminal has its own padding in flushSessionTerminalBatch().
|
||||
const needsPadding = this._isTunnelActive && event === SseEvent.SessionNeedsRefresh;
|
||||
const padding = needsPadding ? SSE_PADDING : '';
|
||||
let message: string;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user