pub mod api;
pub mod bus;
pub mod exec;
pub mod fsops;
pub mod jobs;
pub mod osops;
pub mod peer;
#[cfg(feature = "sysinfo-caps")]
pub mod procs;
pub mod proto;
#[cfg(feature = "pty")]
pub mod pty;
pub mod session;
pub mod store;
#[cfg(feature = "sysinfo-caps")]
pub mod sysmon;
pub mod transport;
pub mod watch;
pub use proto::{Framing, Out, Peer};
pub use session::{caps, Session};
use std::io::Read;
use std::path::PathBuf;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn default_socket() -> PathBuf {
if let Ok(p) = std::env::var("ZWIRE_HOST_SOCK") {
return PathBuf::from(p);
}
#[cfg(windows)]
{
let user = std::env::var("USERNAME").unwrap_or_else(|_| "user".into());
let safe: String = user
.chars()
.filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
.collect();
let name = if safe.is_empty() { "user".into() } else { safe };
PathBuf::from(format!("zwire-host-{name}"))
}
#[cfg(not(windows))]
{
if let Ok(rt) = std::env::var("XDG_RUNTIME_DIR") {
if !rt.is_empty() {
return PathBuf::from(rt).join("zwire-host.sock");
}
}
store::app_dir("zwire").join("host.sock")
}
}
const USAGE: &str = "\
zwire-host — universal local host (system stats · fs · exec · pty · kv · os)
USAGE:
zwire-host native-messaging mode on stdio (Chrome default)
zwire-host serve run the NDJSON socket daemon
zwire-host call '<json>' send one request to the daemon, print reply
zwire-host call ...reading the request JSON from stdin
zwire-host call --stream '...' keep printing frames (sysinfo/pty streams)
zwire-host version | help
OPTIONS:
--socket <path> override the socket path (default: $ZWIRE_HOST_SOCK or
$XDG_RUNTIME_DIR/zwire-host.sock or ~/.zwire/host.sock)
--stream, -f relay every reply frame instead of just the first
--tcp <addr> (serve) also listen for peers/remote clients on TCP
--token <tok> (serve) shared secret required of inbound TCP ($ZWIRE_HOST_TOKEN)
--name <name> (serve) this host's advertised peer name (default: hostname)
--peer <addr> (serve) dial a peer and keep it linked; repeatable
Examples:
zwire-host serve &
zwire-host call '{\"cmd\":\"hostinfo\"}'
zwire-host call '{\"cmd\":\"fs_walk\",\"path\":\"~/src\",\"ext\":\"rs\"}'
echo '{\"cmd\":\"exec\",\"program\":\"git\",\"args\":[\"status\"]}' | zwire-host call
zwire-host call --stream '{\"cmd\":\"sysinfo_start\"}'
zwire-host serve --tcp 0.0.0.0:7420 --token SECRET --peer other.local:7420
";
pub fn run(args: Vec<String>) {
let mut socket = default_socket();
let mut follow = false;
let mut tcp: Option<String> = None;
let mut token: Option<String> = None;
let mut name: Option<String> = None;
let mut peers: Vec<String> = Vec::new();
let mut positional: Vec<String> = Vec::new();
let mut it = args.into_iter();
while let Some(a) = it.next() {
match a.as_str() {
"--socket" | "-s" => {
if let Some(p) = it.next() {
socket = PathBuf::from(p);
}
}
"--stream" | "--follow" | "-f" => follow = true,
"--tcp" => tcp = it.next(),
"--token" => token = it.next(),
"--name" => name = it.next(),
"--peer" => {
if let Some(p) = it.next() {
peers.push(p);
}
}
_ => positional.push(a),
}
}
match positional.first().map(String::as_str) {
Some("serve") => transport::serve(transport::ServeConfig {
socket,
tcp,
token,
name,
peers,
}),
Some("call") => {
let rest = positional[1..].join(" ");
let request = if rest.trim().is_empty() {
let mut s = String::new();
let _ = std::io::stdin().read_to_string(&mut s);
s
} else {
rest
};
transport::call(&socket, &request, follow);
}
Some("version") | Some("--version") | Some("-V") => {
println!("zwire-host {VERSION}");
}
Some("help") | Some("--help") | Some("-h") => {
print!("{USAGE}");
}
_ => transport::stdio(),
}
}