Repository navigation
Description
Story
As a person running commands in xmd repl, I want their stdout and stderr to appear inside the owning round, so command output cannot overwrite the transcript, Sidekick or input controls.
An ordinary command needs no capture binding to protect the interface:
```sh exec
printf 'command output\n'
printf 'command diagnostic\n' >&2
```Both streams are presented through the REPL while the command runs. The terminal layout, focus and any unsent draft remain intact.
Current gap and reproduction
In the reported session a5544ec760b14ac84c36bd563106f292, Entry 3 runs pwd and git status --short --branch in an ordinary sh exec fence. Its command result retains stdout, but its root rendered output is only a newline. The foreground bytes bypass the REPL output view and overwrite the terminal panes.
Entry 4 runs the same commands with as="location" and explicitly renders {location.stdout}. Its root output contains the expected text, which appears in the Output pane. This is a useful negative control, not a workaround authors should need.
Core's ordinary foreground routing forwards both process channels. That behavior is appropriate for xmd run; the interactive REPL does not currently contain that forwarding at its execution boundary.
Contract
- Route foreground stdout and stderr from REPL-owned command execution through the owning round's presentation. Stream output while work is running rather than waiting for exit.
- Only the REPL terminal renderer writes presentation bytes to the physical terminal while the UI owns it. Command text and terminal control sequences cannot draw outside the output surface, clear other panes or change terminal modes.
- Preserve stdout/stderr identity, retained command evidence, exit status, capture bindings and the document's existing output semantics. Captured or hidden output does not become visible merely because the REPL is hosting it; explicitly rendered captured output appears once.
- Credit output to the round that produced it, including late output during cleanup, background Sidekick activity and changes to the selected history position. Output arrival does not move focus, change the selected round or edit a draft.
- Preserve ordinary command forwarding for
xmd runand its stdout/stderr contracts. Implement the REPL display policy through the existing scoped host/process APIs rather than changing global process streams.
Acceptance and evidence
- Reproduce the unbound fence through a mounted production REPL. Verify both streams appear in the owning round while it is running and that every physical terminal write follows the REPL renderer path. The same test fails without the routing fix.
- Compare unbound execution with
as="result"plus explicit interpolation, and with hidden/captured routing. Verify correct visibility, no duplicate output, and unchanged saved stream values and exit status. - Exercise long lines, rapid output, split Unicode, carriage returns and terminal cursor/clear sequences. Neighboring panes and editable drafts remain intact; output remains inspectable within its surface.
- Exercise nonzero exit, cancellation and held cleanup. Preserve diagnostics and existing lifecycle behavior, and never attribute an earlier command's output to a later round.
- Switch history and reopen completed history. Saved command evidence still identifies the correct round and channels; viewing it launches no command.
- Run focused REPL regressions and the existing
xmd runforeground/capture tests. Update the REPL specification to describe the routing and terminal ownership boundary.
Relationships
#1005 owns headless child-session startup and interactive attachment. #1006 owns Sidekick inspection of saved command diagnostics. This issue owns ordinary command output containment in the current interactive REPL; neither broader capability is a prerequisite.
Investigation entrypoints: packages/cli/src/repl/session.ts, packages/core/src/foreground.ts, the exec routing in packages/core/src/execute.ts, and the runtime process/stdio APIs.
Activity