UNPKG

comfyui-mcp

Version:

Local-first, agent-native control plane for ComfyUI — MCP server + autonomous sidebar agent that drives your live graph in natural language on ANY LLM: Claude/ChatGPT/Gemini on your subscription (no API key), free local models via Ollama (fully offline),

65 lines • 2.75 kB
// Live queue-status fan-out for panel/mobile tabs. // // The QueueMonitor watchdog (queue-monitor.ts) already tracks ComfyUI's live // execution state — for EVERY job, including browser-queued ones — but until // now that state never left the orchestrator process. This module turns its // snapshot into a `queue_status` bridge frame so a connected tab (the mobile // app's live queue monitor) can show queue depth + render progress in real // time. // // Throttle contract: the orchestrator ticks the broadcaster on a 1-second // interval, and `tick()` pushes ONLY when the frame differs from the last one // sent. An idle rig therefore broadcasts nothing at all, and a running render // costs at most one frame per second. /** Build the broadcast frame for one monitor snapshot. `completed` overrides * the snapshot's own lastCompleted — used to replay a burst of completions * drained in one tick as distinct frames. */ export function buildQueueStatusFrame(s, completed = s.lastCompleted) { return { type: "queue_status", connected: s.connected, running: s.running, queue_depth: s.queueDepth, prompt_id: s.runningPromptId, node: s.currentNode, progress_value: s.progressValue, progress_max: s.progressMax, last_completed_prompt_id: completed?.promptId ?? null, last_completed_status: completed?.status ?? null, last_completed_at: completed?.at ?? null, }; } /** * Wire a snapshot source to a push sink with change-only semantics. The sink * is the bridge's broadcast push; it must never throw into the timer (the * bridge's own push already guarantees that, see ui-bridge.ts). * * `drainCompletions` (optional) yields runs that finished since the last tick * — each one is replayed as its own frame BEFORE the change-only state frame, * so even a run that started and completed entirely between ticks reaches * every subscriber exactly once (issue #259). The final state frame carries * the newest completion too, so it usually dedupes away. */ export function createQueueStatusBroadcaster(snapshot, push, drainCompletions) { let last = ""; const send = (frame) => { const key = JSON.stringify(frame); if (key === last) return; last = key; push(frame); }; return { tick() { const snap = snapshot(); for (const ev of drainCompletions ? drainCompletions() : []) { send(buildQueueStatusFrame(snap, ev)); } send(buildQueueStatusFrame(snap)); }, current() { return buildQueueStatusFrame(snapshot()); }, }; } //# sourceMappingURL=queue-status-broadcast.js.map