mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-10-03 16:01:59 +00:00
`tty7 exec %N -- CMD` types a line at an existing pane's shell prompt, follows the shell integration's OSC 133 marks to the command's end, prints what it printed (rendered to text by default, `--raw` for the bytes) and exits with its exit code. `--timeout` exits 124 and leaves the command running. A pane with no prompt marks, or one not at a prompt, is refused before anything is typed. `tty7 send` can take its text from `--stdin` or `--from-file`, sent byte for byte and never echoed in --json, so a secret stays out of `ps` and shell history. `--paste` frames the text the way the GUI's paste does: bracketed when the pane has mode 2004 on, unframed otherwise, reported in --json. The framing moves into tty7-core (`core::paste`) so the GUI's clipboard paste, the agent prompt and the CLI share one construction, and the daemon now reports each pane's bracketed-paste mode in PaneContext. Closes #839 Closes #838
67 lines
1.8 KiB
Rust
67 lines
1.8 KiB
Rust
mod address;
|
|
mod backend;
|
|
mod cli;
|
|
mod commands;
|
|
mod exec;
|
|
mod gui;
|
|
mod keys;
|
|
mod output;
|
|
mod resolve;
|
|
mod screen;
|
|
mod server;
|
|
mod stdio;
|
|
#[cfg(test)]
|
|
mod testbed;
|
|
|
|
use clap::Parser;
|
|
|
|
fn main() -> std::process::ExitCode {
|
|
// Before the first byte goes out, and before clap can print a usage error.
|
|
stdio::end_pipelines_quietly();
|
|
let cli = cli::Cli::parse();
|
|
let json = cli.json;
|
|
let quiet = cli.quiet;
|
|
let ctx = address::Context::from_env();
|
|
let mut backend = backend::RealBackend::new(cli.machine.clone());
|
|
match commands::execute(cli, &ctx, &mut backend) {
|
|
// `run` stands in for the command it launched, so its exit code is
|
|
// ours. The report rides along anyway: --json must not go silent just
|
|
// because the verb also carries an exit code.
|
|
Ok(commands::Outcome::Exit(code, report)) => {
|
|
// No flush needed before the exit below: `stdio::out` already did.
|
|
emit(report, json, quiet);
|
|
std::process::exit(code)
|
|
}
|
|
Ok(commands::Outcome::Report(report)) => {
|
|
emit(report, json, quiet);
|
|
std::process::ExitCode::SUCCESS
|
|
}
|
|
// --quiet suppresses output on success, not the reason for a failure:
|
|
// swallowing this leaves a bare exit code and nothing to debug.
|
|
Err(e) => {
|
|
eprintln!("tty7: {e:#}");
|
|
std::process::ExitCode::FAILURE
|
|
}
|
|
}
|
|
}
|
|
|
|
fn emit(report: commands::Report, json: bool, quiet: bool) {
|
|
if quiet {
|
|
return;
|
|
}
|
|
if json {
|
|
if !report.json.is_null() {
|
|
stdio::line(&report.json.to_string());
|
|
}
|
|
} else if !report.human.is_empty() {
|
|
stdio::out(ensure_newline(report.human).as_bytes());
|
|
}
|
|
}
|
|
|
|
fn ensure_newline(mut s: String) -> String {
|
|
if !s.ends_with('\n') {
|
|
s.push('\n');
|
|
}
|
|
s
|
|
}
|