You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the integration ticket — the actual JVM-side terminal renderer that takes a stream of LumosTerminalFrames and writes ANSI escape sequences to stdout (or any provided PrintStream). It implements LumosRenderer<LumosTerminalFrame>, completing the Wave 2 pipeline:
After this ticket, a JVM consumer can run a full loop and see the Lumos orb in their terminal. Wave 3's AMPERE bridge ticket plugs EventSerializerBus into the upstream end of this pipeline.
Objective
A production-quality terminal renderer with cursor management, frame loop, and resize handling, but without stdin (deferred to Wave 5).
Expected Outcomes
CliOrb class at phosphor-lumos-cli/src/jvmMain/kotlin/link/socket/phosphor/lumos/cli/renderer/CliOrb.kt.
clearMode: ClearMode = ClearMode.DIFFERENTIAL — FULL clears the entire orb region each frame, DIFFERENTIAL writes only changed cells.
render(frame: LumosTerminalFrame):
On first render, emit cursor-hide and clear-screen escapes.
Position cursor at orb origin (top-left of orb region).
For each cell, emit cursor position + color escape + character, with run-length optimization (consecutive cells with the same foreground/background skip redundant escapes).
In DIFFERENTIAL mode, compare against the previous frame and skip cells that haven't changed.
Flush at the end of each frame.
start() and stop() lifecycle methods:
start() registers a shutdown hook to call stop().
stop() emits cursor-show, clears the orb region, flushes.
Resize handling via polling: every N frames (configurable, default every 30), re-query terminal dimensions. If changed, clear and re-render fully on next frame. Cross-platform — works on Unix-like and Windows JVMs without signal handlers.
Terminal dimension query: use system properties / JLine / native call, abstracted behind a TerminalSize provider interface so tests can inject fake dimensions.
Unit tests for the rendering logic that capture stdout to a buffer and assert escape sequence output for known frame inputs.
Technical Constraints
JVM-only — lives in jvmMain, not commonMain.
Does not handle stdin. No raw mode. No key bindings.
Does not manage a frame timer or scheduler. Callers drive render() at their preferred cadence. (The targetFps parameter is informational metadata for downstream throttling decisions, not enforced here.)
Resize handling polls; never blocks waiting on signals.
All ANSI escapes use the standard CSI prefix (\u001B[). No vendor-specific extensions.
Whether :phosphor-lumos's common surface includes a LumosRenderTarget.VOXEL_TERMINAL enum value that should be reported by CliOrb.
Available terminal-size detection options on JVM — the project may already have a dependency on JLine or similar; if not, use System.console()-derived heuristics + a fallback to 80×24.
Tasks
Implement TerminalSize provider interface + default JVM implementation that queries terminal dimensions, with 80×24 fallback. Validate: calling the provider returns plausible dimensions on a real terminal; injection of a fake provider works for tests.
Implement render() for FULL clear mode — no diffing, write every cell each frame. Validate: capture stdout, render a known 5×3 frame with one red cell at (2, 1), assert the captured bytes contain the expected escape sequence prefix, cursor position, and character.
Implement run-length optimization (consecutive cells with same color skip redundant color escapes). Validate: capture stdout for a frame of all-red cells; assert only one color escape is emitted, not one per cell.
Implement DIFFERENTIAL clear mode — diff against previous frame, skip unchanged cells. Validate: render frame A then frame A again; second render produces zero cell writes (only cursor parking + flush).
Implement start() and stop() with shutdown hook. Validate: integration test that calls start(), renders, and exits the JVM; shutdown hook runs (verify cursor-show escape was emitted on exit).
Implement resize polling — every N frames, re-query size; if changed, force-clear on next frame. Validate: inject a fake provider that changes size mid-stream; assert next render emits full clear + redraw.
End-to-end smoke test: construct CognitiveSceneRuntime with enableAtmosphere = true, drive it through choreographer transitions IDLE → LISTENING → THINKING → UNCERTAIN → READY, render each settled state via the full pipeline, capture stdout to a file. Manually eyeball the output in a real terminal to confirm visual quality. (This is a developer ergonomics gate, not an automated assertion — but commit a script that produces this output so future regressions are easy to spot.)
Out of Scope
stdin handling, raw mode, keypress capture, interactive demos. Wave 5.
Multiple orbs in the same terminal (split-pane / dashboard layouts). Future ticket.
Inline rendering above other terminal output (e.g., Lumos orb above an agent log stream). Wave 3 (AMPR ticket for ampere-cli integration) handles layout; CliOrb just renders into a region.
Mouse events.
Performance benchmarking under sustained load — Wave 5 polish.
Context
This is the integration ticket — the actual JVM-side terminal renderer that takes a stream of
LumosTerminalFrames and writes ANSI escape sequences to stdout (or any providedPrintStream). It implementsLumosRenderer<LumosTerminalFrame>, completing the Wave 2 pipeline:After this ticket, a JVM consumer can run a full loop and see the Lumos orb in their terminal. Wave 3's AMPERE bridge ticket plugs
EventSerializerBusinto the upstream end of this pipeline.Objective
A production-quality terminal renderer with cursor management, frame loop, and resize handling, but without stdin (deferred to Wave 5).
Expected Outcomes
CliOrbclass atphosphor-lumos-cli/src/jvmMain/kotlin/link/socket/phosphor/lumos/cli/renderer/CliOrb.kt.LumosRenderer<LumosTerminalFrame>(from:phosphor-lumos).out: PrintStream = System.outcolorMode: AnsiColorMode = AnsiColorMode.TRUECOLORtargetFps: Int = 30clearMode: ClearMode = ClearMode.DIFFERENTIAL—FULLclears the entire orb region each frame,DIFFERENTIALwrites only changed cells.render(frame: LumosTerminalFrame):DIFFERENTIALmode, compare against the previous frame and skip cells that haven't changed.start()andstop()lifecycle methods:start()registers a shutdown hook to callstop().stop()emits cursor-show, clears the orb region, flushes.TerminalSizeprovider interface so tests can inject fake dimensions.Technical Constraints
jvmMain, notcommonMain.render()at their preferred cadence. (ThetargetFpsparameter is informational metadata for downstream throttling decisions, not enforced here.)\u001B[). No vendor-specific extensions.AnsiColorMapfrom AnsiColorMap — OKLab to terminal color escape sequences #40.API Surface Verification (before starting)
Confirm in
socket-link/phosphor:LumosRenderer<T>interface signature from Wave 1's Add LumosRenderer interface and VoxelFrame data class #30 — specifically therendermethod name and any lifecycle methods (start/stop/flush).:phosphor-lumos's common surface includes aLumosRenderTarget.VOXEL_TERMINALenum value that should be reported byCliOrb.System.console()-derived heuristics + a fallback to 80×24.Tasks
TerminalSizeprovider interface + default JVM implementation that queries terminal dimensions, with 80×24 fallback. Validate: calling the provider returns plausible dimensions on a real terminal; injection of a fake provider works for tests.render()forFULLclear mode — no diffing, write every cell each frame. Validate: capture stdout, render a known 5×3 frame with one red cell at (2, 1), assert the captured bytes contain the expected escape sequence prefix, cursor position, and character.DIFFERENTIALclear mode — diff against previous frame, skip unchanged cells. Validate: render frame A then frame A again; second render produces zero cell writes (only cursor parking + flush).start()andstop()with shutdown hook. Validate: integration test that callsstart(), renders, and exits the JVM; shutdown hook runs (verify cursor-show escape was emitted on exit).CognitiveSceneRuntimewithenableAtmosphere = true, drive it through choreographer transitions IDLE → LISTENING → THINKING → UNCERTAIN → READY, render each settled state via the full pipeline, capture stdout to a file. Manually eyeball the output in a real terminal to confirm visual quality. (This is a developer ergonomics gate, not an automated assertion — but commit a script that produces this output so future regressions are easy to spot.)Out of Scope
ampere-cliintegration) handles layout;CliOrbjust renders into a region.