1pub mod api;
23pub mod bus;
24pub mod exec;
25pub mod fsops;
26pub mod hostlog;
27pub mod jobs;
28pub mod osops;
29pub mod peer;
30#[cfg(feature = "sysinfo-caps")]
31pub mod procs;
32pub mod proto;
33#[cfg(feature = "pty")]
34pub mod pty;
35pub mod session;
36pub mod store;
37#[cfg(feature = "sysinfo-caps")]
38pub mod sysmon;
39#[cfg(feature = "tauri")]
40pub mod tauri_theme;
41pub mod theme_watch;
42pub mod transport;
43pub mod watch;
44
45pub use proto::{Framing, Out, Peer};
66pub use session::{caps, Session};
67
68use std::io::Read;
69use std::path::PathBuf;
70
71pub const VERSION: &str = env!("CARGO_PKG_VERSION");
73
74pub fn default_socket() -> PathBuf {
87 if let Ok(p) = std::env::var("ZWIRE_HOST_SOCK") {
88 return PathBuf::from(p);
89 }
90 #[cfg(windows)]
91 {
92 let user = std::env::var("USERNAME").unwrap_or_else(|_| "user".into());
93 let safe: String = user
94 .chars()
95 .filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
96 .collect();
97 let name = if safe.is_empty() { "user".into() } else { safe };
98 PathBuf::from(format!("zwire-host-{name}"))
99 }
100 #[cfg(not(windows))]
101 {
102 if let Ok(rt) = std::env::var("XDG_RUNTIME_DIR") {
104 if !rt.is_empty() {
105 return PathBuf::from(rt).join("zwire-host.sock");
106 }
107 }
108 if let Ok(tmp) = std::env::var("TMPDIR") {
112 if !tmp.is_empty() {
113 return PathBuf::from(tmp).join("zwire-host.sock");
114 }
115 }
116 let user = std::env::var("USER").unwrap_or_else(|_| "user".into());
119 let safe: String = user
120 .chars()
121 .filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
122 .collect();
123 let user = if safe.is_empty() { "user".into() } else { safe };
124 PathBuf::from("/tmp").join(format!("zwire-host-{user}.sock"))
125 }
126}
127
128const BANNER: &str = concat!(
130 "\x1b[36m███████╗██╗ ██╗██╗██████╗ ███████╗ ██╗ ██╗ ██████╗ ███████╗████████╗\x1b[0m\n",
131 "\x1b[36m╚══███╔╝██║ ██║██║██╔══██╗██╔════╝ ██║ ██║██╔═══██╗██╔════╝╚══██╔══╝\x1b[0m\n",
132 "\x1b[35m ███╔╝ ██║ █╗ ██║██║██████╔╝█████╗█████╗███████║██║ ██║███████╗ ██║ \x1b[0m\n",
133 "\x1b[35m ███╔╝ ██║███╗██║██║██╔══██╗██╔══╝╚════╝██╔══██║██║ ██║╚════██║ ██║ \x1b[0m\n",
134 "\x1b[31m███████╗╚███╔███╔╝██║██║ ██║███████╗ ██║ ██║╚██████╔╝███████║ ██║ \x1b[0m\n",
135 "\x1b[31m╚══════╝ ╚══╝╚══╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ \x1b[0m\n",
136);
137
138const HELP_BODY: &str = " \x1b[35m>> UNIVERSAL LOCAL HOST // FULL SPECTRUM <<\x1b[0m\n\n universal local host — system stats · fs · exec · pty · kv · os\n\n\x1b[33m USAGE:\x1b[0m zwire-host [MODE] [OPTIONS]\n\n\x1b[36m ── MODES ─────────────────────────────────────────────────────\x1b[0m\n zwire-host \x1b[32m//\x1b[0m native-messaging on stdio (Chrome default)\n zwire-host serve \x1b[32m//\x1b[0m run the NDJSON socket daemon\n zwire-host call '<json>' \x1b[32m//\x1b[0m send one request to the daemon, print reply\n zwire-host call \x1b[32m//\x1b[0m ...reading the request JSON from stdin\n zwire-host call --stream '...' \x1b[32m//\x1b[0m keep printing frames (sysinfo/pty streams)\n zwire-host version | help \x1b[32m//\x1b[0m print version / this help\n\n\x1b[36m ── OPTIONS ───────────────────────────────────────────────────\x1b[0m\n -s, --socket <path> \x1b[32m//\x1b[0m socket ($ZWIRE_HOST_SOCK / $XDG_RUNTIME_DIR / $TMPDIR)\n -f, --stream \x1b[32m//\x1b[0m relay every reply frame instead of just the first\n --tcp <addr> \x1b[32m//\x1b[0m (serve) also listen for peers/remote clients on TCP\n --token <tok> \x1b[32m//\x1b[0m (serve) shared secret required of inbound TCP\n --name <name> \x1b[32m//\x1b[0m (serve) advertised peer name (default: hostname)\n --peer <addr> \x1b[32m//\x1b[0m (serve) dial a peer and keep it linked; repeatable\n -h, --help \x1b[32m//\x1b[0m print this help\n -V, --version \x1b[32m//\x1b[0m print version\n\n\x1b[36m ── EXAMPLES ──────────────────────────────────────────────────\x1b[0m\n zwire-host serve &\n zwire-host call '{\"cmd\":\"hostinfo\"}'\n zwire-host call '{\"cmd\":\"fs_walk\",\"path\":\"~/src\",\"ext\":\"rs\"}'\n echo '{\"cmd\":\"exec\",\"program\":\"git\",\"args\":[\"status\"]}' | zwire-host call\n zwire-host call --stream '{\"cmd\":\"sysinfo_start\"}'\n zwire-host serve --tcp 0.0.0.0:7420 --token SECRET --peer other.local:7420\n";
141
142fn usage() -> String {
146 const BOX_W: usize = 72;
147 let status = format!(" STATUS: ONLINE // SIGNAL: ████████░░ // v{VERSION}");
148 let space = " ".repeat(BOX_W.saturating_sub(status.chars().count()));
149 let rule = "─".repeat(BOX_W);
150 format!(
151 "\n{BANNER} \x1b[36m┌{rule}┐\x1b[0m\n \x1b[36m│\x1b[0m{status}{space}\x1b[36m│\x1b[0m\n \x1b[36m└{rule}┘\x1b[0m\n{HELP_BODY}\n\x1b[36m ── SYSTEM ────────────────────────────────────────────────────\x1b[0m\n \x1b[35mv{VERSION} \x1b[0m// \x1b[33m(c) MenkeTechnologies\x1b[0m\n \x1b[35mOne pipe. One binary. The whole machine.\x1b[0m\n \x1b[33m>>> JACK IN. ONE SOCKET. OWN YOUR MACHINE. <<<\x1b[0m\n \x1b[36m░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\x1b[0m\n"
152 )
153}
154
155pub fn run(args: Vec<String>) {
160 let mut socket = default_socket();
162 let mut follow = false;
163 let mut tcp: Option<String> = None;
164 let mut token: Option<String> = None;
165 let mut name: Option<String> = None;
166 let mut peers: Vec<String> = Vec::new();
167 let mut positional: Vec<String> = Vec::new();
168 let mut it = args.into_iter();
169 while let Some(a) = it.next() {
170 match a.as_str() {
171 "--socket" | "-s" => {
172 if let Some(p) = it.next() {
173 socket = PathBuf::from(p);
174 }
175 }
176 "--stream" | "--follow" | "-f" => follow = true,
177 "--tcp" => tcp = it.next(),
178 "--token" => token = it.next(),
179 "--name" => name = it.next(),
180 "--peer" => {
181 if let Some(p) = it.next() {
182 peers.push(p);
183 }
184 }
185 _ => positional.push(a),
186 }
187 }
188
189 match positional.first().map(String::as_str) {
190 Some("serve") => transport::serve(transport::ServeConfig {
191 socket,
192 tcp,
193 token,
194 name,
195 peers,
196 }),
197 Some("call") => {
198 let rest = positional[1..].join(" ");
199 let request = if rest.trim().is_empty() {
200 let mut s = String::new();
201 let _ = std::io::stdin().read_to_string(&mut s);
202 s
203 } else {
204 rest
205 };
206 transport::call(&socket, &request, follow);
207 }
208 Some("version") | Some("--version") | Some("-V") => {
209 println!("zwire-host {VERSION}");
210 }
211 Some("help") | Some("--help") | Some("-h") => {
212 print!("{}", usage());
213 }
214 _ => transport::stdio(),
216 }
217}