Public: anyone can read this; the crew can change it.
The app page's run log tail appends run.log frames from /events and opens no EventSource of its own #2860
Check · Review · Land · Live done — Landed and live in production.
The app page's log tail now appends `run.log` frames from the page's one `/events` connection and opens no EventSource of its own. I couldn't run `bun x tsc --noEmit` here: bun can't write to its temp dir in this sandbox, so `bun install` failed too. I wrote the test's typings to be strict-safe by hand, including guarded handler calls (`handler?.(...)`), but the forge's check is the first real typ…
shipped production is serving it deploy 2fa0c24
The app page's log tail now appends run.log frames from the page's one /events connection and opens no EventSource of its own. I couldn't run bun x tsc --noEmit here: bun can't write to its temp dir in this sandbox, so bun install failed too. I wrote the test's typings to be strict-safe by hand, including guarded handler calls (handler?.(...)), but the forge's check is the first real type check.
bun test test/app-tail-events.test.ts test/map.test.ts passes.
What changed
- Live client (
src/web/client.ts):connect()inliveRegionsJskeeps the literalnew EventSource('/events'). It now also listens forrun.logand re-dispatches each frame ondocumentasforge:run-log. - Tail (
appTailJs): it reads its run id from itsdata-streamURL and appends the lines of frames for that run, ignoring other runs and malformed frames. The per-runEventSource(url)is gone. The mirror stream at line 126 is untouched. - Test (
test/app-tail-events.test.ts):liveRegionsJsandappTailJsrun against a fake DOM and a fake EventSource. It checks that only/eventsis opened and that arun.logframe for the run appends its two lines once. A frame for another run and a non-JSON frame add nothing.
Left out
- Stop on finish: the tail no longer closes itself on
done. A finished run emits no more frames, and the page's live regions already repaint onrun.*. - Gap between render and first frame: the server renders the tail from the log file, and live frames are lossy by design (#2845). A line can fall in that gap, or be shown twice, and I didn't try to reconcile it.
To try it, open an app page with an agent run in progress. The tail grows while the browser shows a single /events connection.
🤖 Generated with Claude Code
Does what the issue asks: the app page opens one /events connection, the tail appends run.log frames for its run, and the server-rendered first paint and no-JS view are unchanged. The server emits run.log (src/http/sse.ts:250), app.ts loads liveRegionsJs before appTailJs, and the new test would fail without the change. I did not check the screenshots or the preview. Two things I would do next: (1) A line written between the server render and the first frame is lost or shown twice. Close the gap by rendering a cursor or line count into the tail and dropping frames at or below it. (2) Add an aria-live="off" or role="log" with a label to #app-run-tail so screen readers are not flooded, and say what it is. Also check whether the tail needs a visible Pause when someone scrolls up, since add() pins it to the bottom.
The app page's log tail now appends
run.logframes from the page's one/eventsconnection and opens no EventSource of its own. I couldn't runbun x tsc --noEmithere: bun can't write to its temp dir in this sandbox, sobun installfailed too. I wrote the test's typings to be strict-safe by hand, including guarded handler calls (handler?.(...)), but the forge's check is the first real type check.bun test test/app-tail-events.test.ts test/map.test.tspasses.What changed
src/web/client.ts):connect()inliveRegionsJskeeps the literalnew EventSource('/events'). It now also listens forrun.logand re-dispatches each frame ondocumentasforge:run-log.appTailJs): it reads its run id from itsdata-streamURL and appends the lines of frames for that run, ignoring other runs and malformed frames. The per-runEventSource(url)is gone. The mirror stream at line 126 is untouched.test/app-tail-events.test.ts):liveRegionsJsandappTailJsrun against a fake DOM and a fake EventSource. It checks that only/eventsis opened and that arun.logframe for the run appends its two lines once. A frame for another run and a non-JSON frame add nothing.Left out
done. A finished run emits no more frames, and the page's live regions already repaint onrun.*.To try it, open an app page with an agent run in progress. The tail grows while the browser shows a single
/eventsconnection.🤖 Generated with Claude Code
Closes #2854