-
Notifications
You must be signed in to change notification settings - Fork 1
Description
📋 Overview
Implement real-time command output streaming capability for SSH execution, inspired by PR #37 but with enhanced multi-node UI support. Currently, bssh waits for commands to complete before showing any output, making it difficult to monitor long-running operations across multiple nodes.
Note: This issue has been significantly updated to reflect the current implementation status as of v1.4.0. Most planned features have been implemented.
✅ Implementation Status Summary
| Feature | Status | Location |
|---|---|---|
| Core Streaming API | ✅ Complete | src/ssh/tokio_client/channel_manager.rs |
| Independent Stream Management | ✅ Complete | src/executor/stream_manager.rs |
| Simple Output Modes (--stream, --output-dir) | ✅ Complete | src/cli.rs, src/executor/output_mode.rs |
| Interactive TUI (ratatui) | ✅ Complete | src/ui/tui/ |
| Summary View | ✅ Complete | src/ui/tui/views/summary.rs |
| Detail View | ✅ Complete | src/ui/tui/views/detail.rs |
| Split View | ✅ Complete | src/ui/tui/views/split.rs |
| Diff View | ✅ Complete | src/ui/tui/views/diff.rs |
| Progress Parsing | ✅ Complete | src/ui/tui/progress.rs |
| TTY Detection | ✅ Complete | atty dependency |
| Memory Overflow Protection | ✅ Complete | RollingBuffer with 10MB limit |
| Comprehensive Tests | 🚧 Partial | Unit tests exist, more integration tests needed |
| Documentation | 🚧 Partial | Code documented, ARCHITECTURE.md needs update |
🎯 Goals (Updated)
Real-time Output Streaming: Enable streaming of stdout/stderr as commands execute✅ CompleteMulti-node Observability: Provide dynamic UI to monitor multiple nodes simultaneously✅ CompleteIndependent Stream Management: Maintain separate output streams per node✅ CompleteBackward Compatibility: Maintain existing API and behavior✅ Complete
🏗️ Architecture (Current Implementation)
Core Streaming Infrastructure ✅
// Implemented in src/ssh/tokio_client/channel_manager.rs
/// Command output variants for streaming
#[derive(Debug, Clone)]
pub enum CommandOutput {
StdOut(CryptoVec),
StdErr(CryptoVec),
ExitCode(u32),
}
impl Client {
// Existing method (backward compatible) - uses streaming internally
pub async fn execute(&self, cmd: &str) -> Result<CommandExecutedResult>;
// Streaming method
pub async fn execute_streaming(
&self,
command: &str,
sender: Sender<CommandOutput>
) -> Result<u32, Error>;
// Sudo password support
pub async fn execute_with_sudo(
&self,
command: &str,
sender: Sender<CommandOutput>,
sudo_password: &SudoPassword,
) -> Result<u32, Error>;
}Independent Stream Management ✅
// Implemented in src/executor/stream_manager.rs
/// Independent output stream for a single node
pub struct NodeStream {
pub node: Node,
receiver: mpsc::Receiver<CommandOutput>,
stdout_buffer: RollingBuffer, // 10MB max with overflow protection
stderr_buffer: RollingBuffer,
status: ExecutionStatus,
exit_code: Option<u32>,
closed: bool,
}
/// Manager for coordinating multiple node streams
pub struct MultiNodeStreamManager {
streams: Vec<NodeStream>,
}
/// Execution status for a node's command
pub enum ExecutionStatus {
Pending,
Running,
Completed,
Failed(String),
}TUI Architecture ✅
// Implemented in src/ui/tui/
pub mod app; // TuiApp, ViewMode
pub mod event; // Keyboard event handling
pub mod progress; // Progress bar parsing
pub mod terminal_guard; // RAII terminal cleanup
pub mod views; // summary, detail, split, diff
pub enum ViewMode {
Summary, // Show all nodes status
Detail(usize), // Focus on single node
Split(Vec<usize>), // Show multiple nodes in panes
Diff(usize, usize), // Compare two nodes side-by-side
}📐 Multi-node UI (Implemented)
CLI Output Modes ✅
# TUI Mode (default when TTY detected)
$ bssh -C production "apt-get update"
# → Opens interactive TUI with real-time monitoring
# Stream Mode (--stream flag)
$ bssh -C prod --stream "command"
[node1] Starting process...
[node2] Starting process...
[node1] Progress: 50%
# File Mode (--output-dir flag)
$ bssh -C prod --output-dir ./logs "command"
# Creates: ./logs/node1_TIMESTAMP.stdout, etc.
# Normal Mode (auto when piped)
$ bssh -C prod "uptime" | grep -v idleTUI Views (All Implemented) ✅
Summary View (Press Esc from other views)
┌──────────────────────────────────────────────────────────┐
│ Cluster: production - apt-get upgrade │
│ Total: 8 • ✓ 3 • ✗ 1 • 4 in progress │
├──────────────────────────────────────────────────────────┤
│ [1] node1 ✓ Completed (exit: 0) │
│ [2] node2 ⟳ [========= ] 75% │
│ [3] node3 ⟳ Running... │
│ [4] node4 ✗ Exit code: 1 │
│ [5] node5 ⟳ [== ] 25% │
├──────────────────────────────────────────────────────────┤
│ [1-9] Detail [s] Split [d] Diff [q] Quit [?] Help │
└──────────────────────────────────────────────────────────┘
Detail View (Press 1-9)
Full output view with scrolling and follow mode toggle (f key).
Split View (Press s)
Shows 2-4 nodes simultaneously in split panes.
Diff View (Press d)
Side-by-side comparison of two nodes.
Keyboard Controls ✅
1-9: Jump to node detail views: Enter split viewd: Enter diff view (select two nodes)f: Toggle auto-scroll (follow mode)↑/↓: Scroll output←/→: Switch between nodes in detail viewEsc: Return to summary view?: Show help overlayq: Quit
📦 Dependencies (Current)
# Already implemented in Cargo.toml
ratatui = "0.29" # TUI framework
crossterm = "0.29" # Terminal control
atty = "0.2.14" # TTY detection
tokio = { version = "1.47.1", features = ["full"] }
indicatif = "0.18" # Progress indicators (parallel mode)🛠️ Implementation Status
Task 1: Core Streaming API ✅
- Implement
execute_streaming()API - Add
CommandOutputenum with StdOut/StdErr/ExitCode - Implement
CommandOutputBufferfor internal use - Ensure
execute()maintains backward compatibility (uses streaming internally) - Add error type for
JoinError - Add
execute_with_sudo()for sudo password handling
Task 2: Independent Stream Management ✅
- Implement
NodeStreamstruct with independent buffering - Create
MultiNodeStreamManagerfor coordinating streams - Implement non-blocking polling (
poll()method) - Add per-node state management (ExecutionStatus)
- Handle partial failures gracefully
- Add
RollingBufferwith 10MB limit for memory protection
Task 3: Simple Output Modes ✅
- Add
--streamflag for interleaved output with[node]prefixes - Implement
--output-dirfor per-node file output - Add TTY detection (auto-enable TUI in terminals)
- Update CLI argument parsing in
src/cli.rs - Implement
OutputModeenum (Normal/Stream/File/Tui)
Task 4: Interactive TUI ✅
- Add
ratatuiandcrosstermdependencies - Implement summary view component
- Add detail view with node switching
- Implement split view mode (2-4 nodes)
- Add diff mode for comparing two nodes
- Implement progress parsing heuristics
- Add keyboard navigation
- Add auto-scroll control (follow mode)
- Implement help overlay (? key)
- Add terminal size validation with error message
Task 5: Testing & Documentation 🚧
- Unit tests for stream management
- TUI integration tests with ratatui's test backend
- Update ARCHITECTURE.md with TUI architecture
- Add usage examples in README.md
🎁 Additional Features Implemented (Beyond Original Scope)
The following features were implemented but not originally planned in this issue:
-
Sudo Password Support (
execute_with_sudo())- Automatic sudo prompt detection
- Secure password injection with PTY
- Multiple sudo prompt handling (up to 10 per session)
- Buffer size limits for security (64KB)
-
Memory Protection
RollingBufferwith configurable max size (10MB default)- Automatic old data discard to prevent OOM
- Overflow logging and warnings
-
Terminal Guard
- RAII-based terminal cleanup
- Proper handling of crashes/panics
- Cursor visibility management
-
Progress Parsing Heuristics
- Detection of
XX%patterns - Status message extraction from output
- Integration with summary view
- Detection of
🎯 Remaining Work
-
Documentation
- Update ARCHITECTURE.md with new TUI module structure
- Add TUI screenshots to README
- Document keyboard shortcuts in help output
-
Testing
- Add TUI snapshot tests using ratatui's test backend
- Integration tests for streaming execution
- Performance tests for large output handling
-
Future Enhancements (Lower Priority)
- Configurable buffer sizes via CLI/config
- Output search/filtering within TUI
- Session recording and playback
- Per-node selective logging
📁 Current Project Structure (Relevant Files)
bssh/
├── src/
│ ├── cli.rs # CLI with --stream, --output-dir flags
│ ├── executor/
│ │ ├── mod.rs # ParallelExecutor exports
│ │ ├── output_mode.rs # OutputMode enum
│ │ └── stream_manager.rs # NodeStream, MultiNodeStreamManager
│ ├── ssh/
│ │ ├── client/
│ │ │ ├── mod.rs # SshClient exports
│ │ │ ├── command.rs # execute(), execute_streaming()
│ │ │ └── ...
│ │ └── tokio_client/
│ │ ├── mod.rs # Client, CommandOutput exports
│ │ ├── channel_manager.rs # CommandOutput, execute_streaming()
│ │ └── ...
│ ├── ui/
│ │ ├── mod.rs # UI exports
│ │ └── tui/
│ │ ├── mod.rs # run_tui(), TuiExitReason
│ │ ├── app.rs # TuiApp, ViewMode
│ │ ├── event.rs # Keyboard handling
│ │ ├── progress.rs # Progress parsing
│ │ ├── terminal_guard.rs # RAII terminal cleanup
│ │ └── views/
│ │ ├── mod.rs
│ │ ├── summary.rs
│ │ ├── detail.rs
│ │ ├── split.rs
│ │ └── diff.rs
│ └── commands/
│ └── exec.rs # Execute command with output modes
└── Cargo.toml # ratatui, crossterm, atty dependencies
📚 References
- Original PR feat: stream output of executed commands #37: feat: stream output of executed commands #37
- russh documentation: https://docs.rs/russh/
- ratatui documentation: https://docs.rs/ratatui/
- ratatui examples: https://github.com/ratatui-org/ratatui/tree/main/examples
✅ Acceptance Criteria (Status)
-
execute_streaming()API works with single node - Multi-node execution maintains independent streams per node
- Node switching is instant (no re-fetching of output)
- Each node preserves scroll position and state when switching
-
--streammode works in terminals and pipes - TUI activates automatically in interactive terminals
- All existing tests pass (backward compatibility)
- New tests cover streaming scenarios and view modes (partial)
- Documentation updated (README, ARCHITECTURE.md) (partial)