Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: quiet startup output and add persistent linked indicator #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
bigph00t merged 2 commits into main from ux/clearer-bare-session
May 19, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/Cargo.lock
View file Open in desktop

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/Cargo.toml
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mobilecli"
version = "0.2.0"
version = "0.2.1"
description = "Stream your terminal CLIs to your phone - shell hook edition"
authors = ["MobileCLI"]
edition = "2021"
Expand Down
38 changes: 32 additions & 6 deletions cli/src/main.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,19 @@ async fn main() -> ExitCode {
colored::control::set_virtual_terminal(true).ok();
}

// Initialize tracing
// Initialize tracing.
//
// Default to warn so the foreground UX (bare `mobilecli`, `mobilecli claude`,
// etc.) does not flash a wall of info-level logs at session start that then
// get wiped by tmux's alternate screen. Operators can opt back into verbose
// logs with `RUST_LOG=mobilecli=info` or `RUST_LOG=mobilecli=debug`. The
// background daemon process inherits this default but its own stderr is
// redirected to ~/.mobilecli/daemon.log, so its log volume is unchanged from
// the user's perspective.
let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("mobilecli=warn"));
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("mobilecli=info".parse().unwrap()),
)
.with_env_filter(env_filter)
.with_target(false)
.init();

Expand Down Expand Up @@ -253,7 +260,8 @@ async fn main() -> ExitCode {
}

// Determine what command to run
let (command, args) = if run_args.args.is_empty() {
let bare_invocation = run_args.args.is_empty();
let (command, args) = if bare_invocation {
// Use cross-platform shell detection
let shell = platform::default_shell();
(shell, vec![])
Expand All @@ -263,6 +271,24 @@ async fn main() -> ExitCode {
(command, args)
};

// For bare `mobilecli` invocations from an interactive terminal, surface a
// one-line discoverability hint pointing at `mobilecli help`. The hint is
// printed before the session starts and is intentionally short so it does
// not crowd the "Connected!" banner that follows from pty_wrapper.
if bare_invocation && !run_args.quiet {
use std::io::IsTerminal;
if std::io::stdout().is_terminal() {
println!(
"{} Tip: run {} to see commands like {}, {}, {}.",
"β†’".dimmed(),
"`mobilecli help`".cyan(),
"claude".cyan(),
"codex".cyan(),
"pair".cyan()
);
}
}

// Generate session name
let session_name = run_args.session_name.unwrap_or_else(|| {
std::path::Path::new(&command)
Expand Down
34 changes: 34 additions & 0 deletions cli/src/pty_wrapper.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,27 @@ fn request_terminal_resize(cols: u16, rows: u16) {
set_stdout_winsize(cols, rows);
}

/// Set the host terminal window title via OSC 0. Pass an empty string to clear.
///
/// Skipped when stdout is not a TTY to avoid leaking escape sequences into
/// pipes/logs. OSC 0 (`\x1b]0;<title>\x07`) sets both the icon name and the
/// window title and is supported by every mainstream terminal emulator we
/// target. Title characters that could themselves terminate the sequence (BEL,
/// ESC, control bytes) are stripped to avoid corrupting downstream output.
fn set_host_terminal_title(title: &str) {
if !std::io::stdout().is_terminal() {
return;
}
let sanitized: String = title
.chars()
.filter(|c| !c.is_control())
.take(120)
.collect();
let mut stdout = std::io::stdout();
let _ = write!(stdout, "\x1b]0;{}\x07", sanitized);
let _ = stdout.flush();
}

fn tmux_base_command(socket_name: &str) -> Command {
let mut cmd = Command::new("tmux");
// Use platform-appropriate null device
Expand Down Expand Up @@ -655,6 +676,14 @@ pub async fn run_wrapped(config: WrapConfig) -> Result<i32, WrapError> {
);
}

// Set the host terminal window title to advertise the linked state.
// OSC 0 sets both icon name and window title; survives tmux alt-screen
// because tmux's `set-titles` defaults to off (and we leave it off), so
// the host emulator retains whatever title was last set on its stdout.
// The next shell prompt after session end (or our explicit reset below)
// restores a normal title.
set_host_terminal_title(&format!("πŸ“± MobileCLI Β· {}", config.session_name));

// Create PTY
let pty_system = native_pty_system();
let (cols, rows) = get_terminal_size();
Expand Down Expand Up @@ -1177,6 +1206,11 @@ pub async fn run_wrapped(config: WrapConfig) -> Result<i32, WrapError> {
print!("\x1bc");
let _ = std::io::Write::flush(&mut std::io::stdout());

// Clear the MobileCLI window title set at session start. We emit an empty
// OSC 0 string; the next shell prompt (PROMPT_COMMAND/precmd) will set a
// normal title on its own.
set_host_terminal_title("");

// Print exit message
println!();
if exit_code == 0 {
Expand Down
Loading

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /