1pub mod api;
23pub mod bus;
24pub mod exec;
25pub mod fsops;
26pub mod hooks;
27pub mod hostlog;
28pub mod jobs;
29pub mod osops;
30pub mod peer;
31#[cfg(feature = "sysinfo-caps")]
32pub mod procs;
33pub mod proto;
34#[cfg(feature = "pty")]
35pub mod pty;
36pub mod session;
37pub mod store;
38pub mod stryke_lsp;
39pub mod stryke_runner;
40#[cfg(feature = "sysinfo-caps")]
41pub mod sysmon;
42#[cfg(feature = "tauri")]
43pub mod tauri_theme;
44pub mod theme_watch;
45pub mod transport;
46pub mod watch;
47
48pub use proto::{Framing, Out, Peer};
69pub use session::{caps, Session};
70
71use std::io::Read;
72use std::path::PathBuf;
73
74pub const VERSION: &str = env!("CARGO_PKG_VERSION");
76
77pub fn default_socket() -> PathBuf {
90 if let Ok(p) = std::env::var("ZWIRE_HOST_SOCK") {
91 return PathBuf::from(p);
92 }
93 #[cfg(windows)]
94 {
95 let user = std::env::var("USERNAME").unwrap_or_else(|_| "user".into());
96 let safe: String = user
97 .chars()
98 .filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
99 .collect();
100 let name = if safe.is_empty() { "user".into() } else { safe };
101 PathBuf::from(format!("zwire-host-{name}"))
102 }
103 #[cfg(not(windows))]
104 {
105 if let Ok(rt) = std::env::var("XDG_RUNTIME_DIR") {
107 if !rt.is_empty() {
108 return PathBuf::from(rt).join("zwire-host.sock");
109 }
110 }
111 if let Ok(tmp) = std::env::var("TMPDIR") {
115 if !tmp.is_empty() {
116 return PathBuf::from(tmp).join("zwire-host.sock");
117 }
118 }
119 let user = std::env::var("USER").unwrap_or_else(|_| "user".into());
122 let safe: String = user
123 .chars()
124 .filter(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
125 .collect();
126 let user = if safe.is_empty() { "user".into() } else { safe };
127 PathBuf::from("/tmp").join(format!("zwire-host-{user}.sock"))
128 }
129}
130
131const BANNER: &str = concat!(
133 "\x1b[36m███████╗██╗ ██╗██╗██████╗ ███████╗ ██╗ ██╗ ██████╗ ███████╗████████╗\x1b[0m\n",
134 "\x1b[36m╚══███╔╝██║ ██║██║██╔══██╗██╔════╝ ██║ ██║██╔═══██╗██╔════╝╚══██╔══╝\x1b[0m\n",
135 "\x1b[35m ███╔╝ ██║ █╗ ██║██║██████╔╝█████╗█████╗███████║██║ ██║███████╗ ██║ \x1b[0m\n",
136 "\x1b[35m ███╔╝ ██║███╗██║██║██╔══██╗██╔══╝╚════╝██╔══██║██║ ██║╚════██║ ██║ \x1b[0m\n",
137 "\x1b[31m███████╗╚███╔███╔╝██║██║ ██║███████╗ ██║ ██║╚██████╔╝███████║ ██║ \x1b[0m\n",
138 "\x1b[31m╚══════╝ ╚══╝╚══╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ \x1b[0m\n",
139);
140
141const 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";
144
145fn usage() -> String {
149 const BOX_W: usize = 72;
150 let status = format!(" STATUS: ONLINE // SIGNAL: ████████░░ // v{VERSION}");
151 let space = " ".repeat(BOX_W.saturating_sub(status.chars().count()));
152 let rule = "─".repeat(BOX_W);
153 format!(
154 "\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"
155 )
156}
157
158pub fn run(args: Vec<String>) {
163 let mut socket = default_socket();
165 let mut follow = false;
166 let mut tcp: Option<String> = None;
167 let mut token: Option<String> = None;
168 let mut name: Option<String> = None;
169 let mut peers: Vec<String> = Vec::new();
170 let mut positional: Vec<String> = Vec::new();
171 let mut it = args.into_iter();
172 while let Some(a) = it.next() {
173 match a.as_str() {
174 "--socket" | "-s" => {
175 if let Some(p) = it.next() {
176 socket = PathBuf::from(p);
177 }
178 }
179 "--stream" | "--follow" | "-f" => follow = true,
180 "--tcp" => tcp = it.next(),
181 "--token" => token = it.next(),
182 "--name" => name = it.next(),
183 "--peer" => {
184 if let Some(p) = it.next() {
185 peers.push(p);
186 }
187 }
188 _ => positional.push(a),
189 }
190 }
191
192 match positional.first().map(String::as_str) {
193 Some("serve") => transport::serve(transport::ServeConfig {
194 socket,
195 tcp,
196 token,
197 name,
198 peers,
199 }),
200 Some("call") => {
201 let rest = positional[1..].join(" ");
202 let request = if rest.trim().is_empty() {
203 let mut s = String::new();
204 let _ = std::io::stdin().read_to_string(&mut s);
205 s
206 } else {
207 rest
208 };
209 transport::call(&socket, &request, follow);
210 }
211 Some("version") | Some("--version") | Some("-V") => {
212 println!("zwire-host {VERSION}");
213 }
214 Some("help") | Some("--help") | Some("-h") => {
215 print!("{}", usage());
216 }
217 _ => transport::stdio(),
219 }
220}