({
executeInput,
}: ProcessQueueParams)
| 50 | * @returns result with processed status |
| 51 | */ |
| 52 | export function processQueueIfReady({ |
| 53 | executeInput, |
| 54 | }: ProcessQueueParams): ProcessQueueResult { |
| 55 | // This processor runs on the REPL main thread between turns. Skip anything |
| 56 | // addressed to a subagent — an unfiltered peek() returning a subagent |
| 57 | // notification would set targetMode, dequeueAllMatching would find nothing |
| 58 | // matching that mode with agentId===undefined, and we'd return processed: |
| 59 | // false with the queue unchanged → the React effect never re-fires and any |
| 60 | // queued user prompt stalls permanently. |
| 61 | const isMainThread = (cmd: QueuedCommand) => cmd.agentId === undefined |
| 62 | |
| 63 | const next = peek(isMainThread) |
| 64 | if (!next) { |
| 65 | return { processed: false } |
| 66 | } |
| 67 | |
| 68 | // Slash commands and bash-mode commands are processed individually. |
| 69 | // Bash commands need per-command error isolation, exit codes, and progress UI. |
| 70 | if (isSlashCommand(next) || next.mode === 'bash') { |
| 71 | const cmd = dequeue(isMainThread)! |
| 72 | void executeInput([cmd]) |
| 73 | return { processed: true } |
| 74 | } |
| 75 | |
| 76 | // Drain all non-slash-command items with the same mode at once. |
| 77 | const targetMode = next.mode |
| 78 | const commands = dequeueAllMatching( |
| 79 | cmd => isMainThread(cmd) && !isSlashCommand(cmd) && cmd.mode === targetMode, |
| 80 | ) |
| 81 | if (commands.length === 0) { |
| 82 | return { processed: false } |
| 83 | } |
| 84 | |
| 85 | void executeInput(commands) |
| 86 | return { processed: true } |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Checks if the queue has pending commands. |
no test coverage detected