Skip to content

Commit 61fdb92

Browse files
authored
feat: add comprehensive configuration management for interactive mode (#10)
* feat: add comprehensive configuration management for interactive mode - Add InteractiveConfig struct with mode, prompt, timestamps, and prefix settings - Support global and per-cluster interactive configuration in config.yaml - CLI arguments override configuration file settings - Add configuration save/update functionality with preferences persistence - Support customizable command prefixes for special commands - Update documentation in --help, README.md, and manpage - Add tests for configuration loading, merging, and saving * fix: add missing fields to InteractiveCommand struct initialization in tests * update: remove osv-scanner since it does not work
1 parent 330d9f0 commit 61fdb92

12 files changed

Lines changed: 725 additions & 91 deletions

File tree

.github/workflows/osv-scanner.yml

Lines changed: 0 additions & 48 deletions
This file was deleted.

README.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,36 @@ defaults:
198198
ssh_key: ~/.ssh/id_rsa
199199
parallel: 10
200200

201+
# Global interactive mode settings (optional)
202+
interactive:
203+
default_mode: multiplex # single_node or multiplex
204+
prompt_format: "[{node}] $ " # Variables: {node}, {user}, {host}, {pwd}
205+
history_file: ~/.bssh_history
206+
show_timestamps: false # Show timestamps in output
207+
work_dir: /home/admin # Initial working directory
208+
broadcast_prefix: "!all " # Prefix for broadcasting to all nodes
209+
node_switch_prefix: "!" # Prefix for special commands
210+
colors: # Node-specific colors in output
211+
node1: red
212+
node2: blue
213+
node3: green
214+
keybindings:
215+
switch_node: "Ctrl+N"
216+
broadcast_toggle: "Ctrl+B"
217+
quit: "Ctrl+Q"
218+
201219
clusters:
202220
production:
203221
nodes:
204222
- web1.example.com
205223
- web2.example.com
206224
- user@web3.example.com:2222
207225
ssh_key: ~/.ssh/prod_key
226+
# Cluster-specific interactive settings (overrides global)
227+
interactive:
228+
default_mode: single_node
229+
prompt_format: "prod> "
230+
work_dir: /var/www
208231

209232
staging:
210233
nodes:
@@ -282,6 +305,38 @@ bssh -H server1,server2 interactive --prompt-format "{user}@{host}> "
282305
bssh -c staging interactive --work-dir /var/www
283306
```
284307

308+
#### Interactive Mode Configuration
309+
310+
Interactive mode can be configured in your `config.yaml` file with both global and per-cluster settings. CLI arguments always override configuration file settings.
311+
312+
**Global Configuration** (applies to all clusters unless overridden):
313+
```yaml
314+
interactive:
315+
default_mode: multiplex # or single_node
316+
prompt_format: "[{node}] $ "
317+
history_file: ~/.bssh_history
318+
show_timestamps: true # Add timestamps to output
319+
work_dir: /home/user
320+
broadcast_prefix: "!all " # Custom prefix for broadcast commands
321+
node_switch_prefix: "!" # Custom prefix for special commands
322+
```
323+
324+
**Per-Cluster Configuration** (overrides global settings):
325+
```yaml
326+
clusters:
327+
production:
328+
interactive:
329+
default_mode: single_node # Different mode for this cluster
330+
prompt_format: "PROD> "
331+
work_dir: /var/app
332+
```
333+
334+
**Configuration Priority**:
335+
1. CLI arguments (highest priority)
336+
2. Cluster-specific configuration
337+
3. Global configuration
338+
4. Built-in defaults
339+
285340
In multiplex mode, commands are sent to active nodes with visual indicators:
286341
287342
```
@@ -294,7 +349,7 @@ In multiplex mode, commands are sent to active nodes with visual indicators:
294349

295350
#### Interactive Mode Special Commands
296351

297-
Interactive mode supports special commands (starting with `!`) for node management:
352+
Interactive mode supports special commands for node management. By default, these commands start with `!` but the prefix can be customized in the configuration file.
298353

299354
| Command | Description |
300355
|---------|-------------|
@@ -306,6 +361,13 @@ Interactive mode supports special commands (starting with `!`) for node manageme
306361
| `!help` or `!?` | Show help for special commands |
307362
| `exit` | Exit interactive mode |
308363

364+
**Note**: The `!` prefix and `!broadcast` command can be customized via configuration:
365+
```yaml
366+
interactive:
367+
node_switch_prefix: "@" # Use @ instead of !
368+
broadcast_prefix: "@all " # Use @all instead of !broadcast
369+
```
370+
309371
#### Node Indicators in Prompt
310372
311373
The prompt shows node status with visual indicators:

docs/man/bssh.1

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,31 @@ Each downloaded file is saved with a unique name prefixed by the hostname.
116116
Uses SFTP protocol for secure file transfer with progress indicators.
117117
.RE
118118

119+
.TP
120+
.B interactive
121+
Start an interactive shell session on cluster nodes
122+
.RS
123+
Usage: bssh interactive [\fIOPTIONS\fR]
124+
.br
125+
Opens an interactive shell session with one or more remote hosts. Supports both single-node
126+
and multiplex modes. In multiplex mode, commands are sent to all active nodes simultaneously.
127+
.PP
128+
Options:
129+
.IP "\-\-single\-node"
130+
Connect to a single node instead of multiplexing to all nodes
131+
.IP "\-\-multiplex"
132+
Multiplex input across all nodes (default behavior)
133+
.IP "\-\-prompt\-format FORMAT"
134+
Custom prompt format with variables: {node}, {user}, {host}, {pwd}
135+
.IP "\-\-history\-file PATH"
136+
History file path for command history (default: ~/.bssh_history)
137+
.IP "\-\-work\-dir DIR"
138+
Initial working directory on remote hosts
139+
.PP
140+
Interactive mode settings can be configured globally or per-cluster in the configuration file.
141+
CLI arguments override configuration file settings.
142+
.RE
143+
119144
.SH CONFIGURATION
120145
.B bssh
121146
loads configuration from the following sources in priority order:
@@ -137,13 +162,28 @@ defaults:
137162
ssh_key: ~/.ssh/id_rsa
138163
parallel: 10
139164

165+
# Global interactive mode settings (optional)
166+
interactive:
167+
default_mode: multiplex # single_node or multiplex
168+
prompt_format: "[{node}] $ " # Variables: {node}, {user}, {host}, {pwd}
169+
history_file: ~/.bssh_history
170+
show_timestamps: false # Show timestamps in output
171+
work_dir: /home/admin # Initial working directory
172+
broadcast_prefix: "!all " # Prefix for broadcasting to all nodes
173+
node_switch_prefix: "!" # Prefix for special commands
174+
140175
clusters:
141176
production:
142177
nodes:
143178
- web1.example.com
144179
- web2.example.com
145180
- user@web3.example.com:2222
146181
ssh_key: ~/.ssh/prod_key
182+
# Cluster-specific interactive settings (overrides global)
183+
interactive:
184+
default_mode: single_node
185+
prompt_format: "prod> "
186+
work_dir: /var/www
147187

148188
staging:
149189
nodes:
@@ -271,6 +311,50 @@ Download logs with wildcard pattern:
271311
Downloads all files matching app*.log from /var/log/ on each node
272312
.RE
273313

314+
.TP
315+
Start interactive mode with all nodes:
316+
.B bssh -c production interactive
317+
.RS
318+
Opens an interactive shell session with all nodes in multiplex mode
319+
.RE
320+
321+
.TP
322+
Start interactive mode with single node:
323+
.B bssh -c production interactive --single-node
324+
.RS
325+
Prompts to select one node for interactive session
326+
.RE
327+
328+
.TP
329+
Interactive mode with custom prompt:
330+
.B bssh -H server1,server2 interactive --prompt-format "{user}@{host}> "
331+
332+
.TP
333+
Interactive mode with initial working directory:
334+
.B bssh -c staging interactive --work-dir /var/www
335+
.RS
336+
Sets initial working directory to /var/www on all nodes
337+
.RE
338+
339+
.SS Interactive Mode Special Commands
340+
When in interactive mode, the following special commands are available (default prefix is !):
341+
.IP "!all"
342+
Activate all connected nodes
343+
.IP "!broadcast <cmd>"
344+
Execute command on all nodes temporarily
345+
.IP "!node<N>"
346+
Switch to node N (e.g., !node1, !node2)
347+
.IP "!list"
348+
List all nodes with their connection status
349+
.IP "!status"
350+
Show currently active nodes
351+
.IP "!help"
352+
Show help for special commands
353+
.IP "exit"
354+
Exit interactive mode
355+
.PP
356+
Note: The special command prefix can be customized in the configuration file.
357+
274358
.SH EXIT STATUS
275359
.TP
276360
.B 0

examples/interactive_demo.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! Example demonstrating interactive mode usage with bssh
1616
1717
use bssh::commands::interactive::InteractiveCommand;
18-
use bssh::config::Config;
18+
use bssh::config::{Config, InteractiveConfig};
1919
use bssh::node::Node;
2020
use std::path::PathBuf;
2121

@@ -46,6 +46,8 @@ async fn main() -> anyhow::Result<()> {
4646
work_dir: None,
4747
nodes,
4848
config: Config::default(),
49+
interactive_config: InteractiveConfig::default(),
50+
cluster_name: None,
4951
};
5052

5153
println!("Starting interactive session...");

src/cli.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,36 +138,41 @@ pub enum Commands {
138138
recursive: bool,
139139
},
140140

141-
#[command(about = "Start interactive shell session")]
141+
#[command(
142+
about = "Start interactive shell session\n\nInteractive mode settings can be configured globally or per-cluster in the configuration file.\nCLI arguments override configuration file settings."
143+
)]
142144
Interactive {
143145
#[arg(
144146
long,
145-
help = "Connect to a single node instead of multiplexing to all nodes"
147+
help = "Connect to a single node instead of multiplexing to all nodes (overrides config)"
146148
)]
147149
single_node: bool,
148150

149151
#[arg(
150152
long,
151153
default_value = "true",
152-
help = "Multiplex input across all nodes (default behavior)"
154+
help = "Multiplex input across all nodes (default behavior, overrides config)"
153155
)]
154156
multiplex: bool,
155157

156158
#[arg(
157159
long,
158160
default_value = "[{node}:{user}@{host}:{pwd}]$ ",
159-
help = "Custom prompt format"
161+
help = "Custom prompt format with variables: {node}, {user}, {host}, {pwd} (overrides config)"
160162
)]
161163
prompt_format: String,
162164

163165
#[arg(
164166
long,
165167
default_value = "~/.bssh_history",
166-
help = "History file path for command history"
168+
help = "History file path for command history (overrides config)"
167169
)]
168170
history_file: PathBuf,
169171

170-
#[arg(long, help = "Initial working directory on remote hosts")]
172+
#[arg(
173+
long,
174+
help = "Initial working directory on remote hosts (overrides config)"
175+
)]
171176
work_dir: Option<String>,
172177
},
173178
}

0 commit comments

Comments
 (0)