feat(hub): stream a hub create's progress back to the PC - #276
Merged
Conversation
A cloud create routed to the control box showed one spinner line stuck on "remote hub: running" for the whole build: the job row carries a status and nothing else, while the worker's real per-step lines only existed as a file on the VPS. Tail that file over the same admin-gated surface the create already uses (`GET /remote/boxes/:id/logs?offset=`), drain it from `pollHubJob` between status checks, and render it on the same self-updating line a local create uses (`-v` streams the full log). The whole transcript now also lands in ~/.agentbox/logs/<command>.log, which was empty for hub runs. Claude-Session: https://claude.ai/code/session_01QUnCvB6dh6JWknXFi5pSzk
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
`readJobLog` is injectable, so the route is the trust boundary: an implementation that forgot the check would inherit a path traversal straight off the URL. Gate there (400) and keep the reader's own check. Claude-Session: https://claude.ai/code/session_01QUnCvB6dh6JWknXFi5pSzk
Owner
Author
|
bugbot run |
Any non-ok response killed tailing for the rest of the wait, so one proxy 502 or connection reset dropped a minutes-long create back to a static status line. Only 404/405/501 (a hub that has no log route at all) is permanent now; anything else skips the tick and retries from the same offset. Claude-Session: https://claude.ai/code/session_01QUnCvB6dh6JWknXFi5pSzk
Owner
Author
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 58d401f. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
agentbox e2b claude(andcreate --via-hub,codex,opencode) routed to a control box showed one spinner line stuck onremote hub: runningfor the 5-10 minutes a cloud create takes. The job row (CreateJobRow) carries a status string and a terminal result — nothing else — so the poll loop could only ever report two transitions.The progress already exists: the hub worker appends every step (lease, clone, seed overlay, the provider's own create output) to
~/.agentbox/logs/queue-<jobId>.logon the control box, which the hub web UI streams. The PC never fetched it, and~/.agentbox/logs/<command>.logwas effectively empty for hub runs.What
GET /remote/boxes/:id/logs?offset=<bytes>on the same admin-bearer-gated dispatcher the create already uses. Returns{ lines, offset }; the offset only ever advances past complete lines, so a read landing mid-line never truncates or drops one. The dispatcher stays fs-free: the daemon injectsreadJobLog(job-log-tail.ts), the serverless plane doesn't and answers 501. Job ids are validated before any path join.pollHubJobgainsonLog, draining the tail between status checks (2s tick when tailing) and once more after the terminal status. A hub without the route (404/405/501) disables tailing silently and the create proceeds status-only.withHubJobLinenow usesmakeProgressReporter, the same helper the local create path uses: collapsed self-updating line by default, full streamed lines under-v. Every line is teed to~/.agentbox/logs/<command>.log; the background-ihub path passed noonLogat all before, so that log was empty.Verification
pnpm build,pnpm typecheck,pnpm lint, full test suite green. New unit tests: route (offset, 501 without the reader, 401 before reading),readCreateJobLog(partial line held back, truncation restart, traversal refused), and the CLI poll (offset progression, graceful fallback on an old hub).pollHubJobagainst a real job log written with deliberate partial lines — all lines delivered in order, none duplicated or truncated.create --provider e2b --via-hubagainst a stand-in control box (relay daemon + a worker that writes the same per-job log). The spinner tracks the worker's lines through tobox ready: e2b-7a1f; all 7 lines land in~/.agentbox/logs/create.log;-vstreams them unclamped.Not run: a real cloud create through a deployed VPS hub — the worker-side log writing is unchanged code (the hub UI consumes the same file).
Docs
apps/web/content/docs/deployed-hub.mdx(what you see while waiting,-v, the local transcript) anddocs/architecture.md(the new route).https://claude.ai/code/session_01QUnCvB6dh6JWknXFi5pSzk
Note
Low Risk
Observability and UX around an existing admin-gated create queue; log read failures are non-fatal and job IDs are validated before any path join.
Overview
Hub-routed creates (
create --via-hub, foreground/backgroundclaude/codex/opencode) no longer sit on a staticremote hub: runningline for minutes. The relay addsGET /remote/boxes/:id/logs?offset=<bytes>(admin-bearer, same surface as create) so the CLI can tail the worker’s per-step log; the daemon wiresreadCreateJobLogfromjob-log-tail.ts, while planes without a log file answer 501 and polling falls back to status-only.pollHubJobgainsonLog: it drains new lines between status ticks (2s when tailing), retries transient log errors, stops tailing only when the hub permanently lacks logs, and does a final drain when the job finishes.hubLogSinkfeeds the live status line (ISO timestamps stripped) and~/.agentbox/logs/<command>.log(verbatim).withHubJobLinenow usesmakeProgressReporterwith-vfor full streamed output, matching local creates; agent hub paths that omittedonLognow tee worker output into the command log.Reviewed by Cursor Bugbot for commit 58d401f. Configure here.