Previously the right column rendered the mode toggle on its own line
above each panel's status/action row, leaving an awkward double-row
header. Now each panel accepts a `leading` slot and hosts the toggle
inline with its existing status pill / breadcrumbs and action buttons,
so Terminal/Filesystem/VNC each occupy a single tight header row.
Also lands a quiet DEFAULT_DIR change in the filesystem panel from
/workspace to /, matching how non-clone sandboxes (and Daytona's image
layout) actually expose the working tree, plus matching test updates.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a third right-column mode (Terminal | Filesystem | VNC) gated to
Daytona sandboxes. The panel POSTs /api/v1/runs/:id/sandbox/vnc, embeds
the signed noVNC preview URL in an iframe with clipboard + fullscreen
allowed, and renders distinct states for unsupported provider (Docker
hides the tab entirely), 409 startup failure (recoverable, "Try again"),
and 404/501 (non-recoverable). A reconnect button refetches the signed
URL when it expires.
Also fixes a Filesystem regression: the previous "skip first effect"
ref guard meant @pierre/trees never received its first resetPaths call
when the listing transitioned from empty to populated, leaving the tree
stuck on the initial empty model. Now the model is always synced via
resetPaths whenever the listing changes; verified live against a
Daytona /workspace + / listing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a Filesystem right-column mode alongside Terminal in /runs/:id/sandbox,
selectable via ?mode=filesystem. The persistent SandboxDetails left column
stays visible in both modes. Browses the run sandbox via the existing
list/get file endpoints, previews text files with @pierre/diffs, and falls
back to download-only for binary, oversized, and unreadable files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make run.created the projection anchor and require canonical run spec/status fields in API and clients.
Collapse diff/checkpoint/conclusion payloads around RunDiff and update server, CLI, workflow, store, and generated clients.
Combines the run detail Sandbox and Terminal tabs into one. Sandbox
details sit in a narrow left column and the terminal fills the wider
right column, separated by a vertical divider that runs from the tab
nav down to the steer bar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds /runs/:id/sandbox between Files Changed and Terminal, gated by
the same sandbox-presence check as Terminal. The route fetches
SandboxDetails through a new useRunSandboxDetails SWR hook and renders
provider-neutral panels for Overview, Resources, Labels, and
Timestamps. Null fields render as muted em dashes.
Returns sandbox_details for the run-owned sandbox. Maps internal errors
into the HTTP shape required by the OpenAPI contract: 404 when the run
or sandbox record is missing, 501 when the provider has no details
implementation, 409 when an existing provider's inspection fails.
Adds fabro_sandbox::sandbox_details, a control-plane inspection function
that maps Local, Docker, and Daytona providers into a shared
SandboxDetails record (state, image, resources, labels, timestamps).
To avoid type sprawl, the demo board's SandboxResources is unified with
the new control-plane shape (cpu_cores: f64, memory_bytes: u64,
disk_bytes: u64). The runs board chip in apps/fabro-web converts
memory_bytes back to GB for display.
Introduces a provider-neutral SandboxDetails record (state, image,
resources, labels, timestamps) plus a normalized SandboxState enum and
the GET /api/v1/runs/{id}/sandbox operation. The fabro-api crate reuses
the fabro-types definitions through with_replacement, and a new
parity round-trip test asserts type identity and JSON shape.
Renders a Gantt-style strip below the Thread toolbar on agent and prompt
stages only. Bar position encodes start time and width encodes duration,
so empty stretches in the strip are real dead time (idle waits, sandbox
spin-up, time waiting on a human steer). Categories collapse to five
colors: system/agent/tool/user/interrupt. Tool/command bars use their
explicit durationMs; tool groups span first child's start to last
child's end so dead time between grouped tools is honored; assistant
bars span the gap from the previous activity's end to the message ts as
an approximation of "thinking" time; system/steer/interrupt are 4 px
instant markers. Hover shows kind/label/elapsed/duration in a portaled
popover; click selects the matching turn or tool group and shares state
with the existing event list and side panel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Server-typed errors like "Local sandboxes do not support embedded
terminals" won't change on retry, so the ErrorState now omits the
"Try again" button for them. WebSocket connection failures stay
recoverable and keep the retry affordance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the stray red caption + empty terminal frame with the shared
ErrorState card so errors like "Local sandboxes do not support embedded
terminals" land in a clear, retry-able panel instead of floating above a
misleading blank terminal.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The outer scroll container had pt-2 with pb-[calc(1.5rem+dock)], so
content sat ~8px below the tab toolbar but ~24px above the dock —
visibly off. Each new renderer also re-applied its own pt-2, doubling
the top spacing. Bump the outer pt to pt-6 so it matches the 24px
baseline bottom, and drop the duplicated pt-2 from every renderer
wrapper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tighten the meta bar (drop redundant labels, fold timestamp into the
duration tooltip), elevate the wait card to a centered hero clock,
strengthen the conditional view with the actual chosen edge and
condition expression sourced from run-level edge.selected events,
upgrade the fan-in selected card with a trophy badge and gradient, and
redesign the parallel stat strip with toned numbers and a duration
column.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders a full-width strip below the Debug toolbar with one bar per
event placed by elapsed time. Hover shows category/name/elapsed;
click opens the event in the side panel. Collapses event categories
to five colors (agent/command/lifecycle/human/system) and shows the
event count persistently on Debug so the strip's density has a number
next to it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the raw Debug fallback for human, conditional, parallel,
parallel.fan_in, stack.manager_loop, and wait stages with purpose-built
views — Q&A transcript, decision card, children grid, fan-in results
with reducer transcript, cycle summary, and live waiter clock. Add a
generic Summary card as the new default for any unknown handler so
future StageHandler additions get a usable view for free. Debug tab
remains as the escape hatch on every handler.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Allow forced run deletion to purge durable metadata even when projection replay fails, and add a repair command path for deleting unreadable runs in batch.
Give the terminal wrapper pb-3 so the active console no longer hugs
the bottom edge of the bordered frame.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The xterm.js renderer cell height is fontSize (13) × lineHeight (1.45)
= 18.85px — non-integer. FitAddon proposes N rows where
N × cellHeight <= available height, but sub-pixel rounding in the
renderer (and font-load timing on first paint) lets the Nth row
extend past the wrapper's content edge, so the last visible line
gets half-clipped.
Reserve one row of buffer in the fit calculation (proposed.rows - 1)
so xterm is never asked to render right up to the bottom edge. The
re-fit on document.fonts.ready stays in place; sendResize now reads
terminal.cols/rows directly so the server sees the same dimensions
xterm actually uses.
Trade-off: ~18px less visible terminal area. The alternative is
switching to an integer cell height (e.g. lineHeight 18/13), which
we can revisit if the lost row matters.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace heading + status badge with a single status pill that folds in the sandbox provider
- Make Reconnect an icon-only button with tooltip; keep SSH labeled
- Darken the terminal canvas and brighten the ANSI palette for higher contrast
- Trim the static gap above the steer-bar dock from 0.5rem to 0.25rem
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs with only non-billable stages rendered as a header + empty body
+ all-dashes "Total" row, which looked broken. Show the existing
EmptyState panel ("No model usage") instead, keeping the original
"No stages yet" message for runs that haven't started executing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expose a run-scoped websocket terminal for Docker and Daytona sandboxes, and add the web terminal route so sandbox-backed runs can be inspected interactively from the run detail page.
Store live per-stage token counts on StageProjection, carry typed billing model identity through agent.message events, and derive billing rollups from the projection so in-flight stages can report usage before terminal events arrive.