UNPKG

framework

Version:

The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.

76 lines 3 kB
/** * The live-chat message channel (#714): the user's own turns into a running run. * * A run's await gates (#337) are the agent asking the user; this is the reverse — * the user speaking to the agent unprompted. Each message continues the *same* * agent session (`claude --resume <id>`), so the conversation keeps its full * context. The run loop drains this once the work settles; a daemon-spawned * session then ends itself when the queue is idle (#1390) — a follow-up message * reopens the conversation via `--resume`, like Claude Code web — while a run * with its own terminal dashboard keeps the old stay-open wait, since that * surface has no daemon to resume through. * * Wired only when an interactive channel can deliver messages (a live dashboard / * daemon over `control.jsonl`). A headless run gets no {@link RunMessages}, so its * loop ends when the agent stops asking — byte-identical to before this existed. */ /** * A {@link RunMessages} the control channel feeds ({@link push}) and the run loop * drains ({@link next}). A message that arrives with a waiter parked hands off * directly; otherwise it queues until the next `next()`. FIFO in both directions. */ export class RunMessageQueue { pending = []; waiters = []; closed = false; /** * Enqueue a user message (or hand it to a parked waiter). No-op once closed. `via` names the * surface it came through (#917); omitted, the run attributes it to its own. */ push(text, via) { if (this.closed) return; const message = via === undefined ? { text } : { text, via }; const waiter = this.waiters.shift(); if (waiter) waiter(message); else this.pending.push(message); } /** Stop the chat: wake every parked waiter with `undefined` so their loops end. */ close() { this.closed = true; let waiter; while ((waiter = this.waiters.shift())) waiter(undefined); } takeQueued() { if (this.closed) return undefined; return this.pending.shift(); } next(signal) { const queued = this.pending.shift(); if (queued !== undefined) return Promise.resolve(queued); if (this.closed || signal?.aborted) return Promise.resolve(undefined); return new Promise(resolve => { const waiter = (message) => { if (signal) signal.removeEventListener('abort', onAbort); resolve(message); }; const onAbort = () => { const i = this.waiters.indexOf(waiter); if (i >= 0) this.waiters.splice(i, 1); resolve(undefined); }; this.waiters.push(waiter); if (signal) signal.addEventListener('abort', onAbort, { once: true }); }); } } //# sourceMappingURL=run-messages.js.map