mirror of
https://github.com/dmduran12/pymc_console-dist.git
synced 2026-07-06 09:51:50 +02:00
5b9dc05ab0
Automated sync from private repository. Built with obfuscation enabled.
2 lines
105 KiB
JavaScript
2 lines
105 KiB
JavaScript
var e=Object.defineProperty,t=(t,r,a)=>((t,r,a)=>r in t?e(t,r,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[r]=a)(t,"symbol"!=typeof r?r+"":r,a);import{j as r,r as a,X as s,c as n,x as o,d as i}from"./vendor-react-Co0R0q1H.js";import{D as c,o as l,L as d}from"./xterm-Cq-DlOOL.js";import{c as u,Z as p,bl as m,bH as h,bI as g,bJ as f,bK as y,n as x,bL as v,bM as $,bN as b,bd as w,ae as _,bO as k,a5 as C,a4 as S,aI as j,bP as N,bQ as T,bR as R,bz as M,Y as E,bS as A,_ as I,B as F,A as L,m as B,bT as D,bU as O,bb as P,v as U,bV as H,bW as z,bX as q}from"./index-BM4uXpTw.js";import{s as K}from"./signal-scoring-CcBiRcks.js";import{h as W,c as G}from"./geo-utils-BR5NTbzq.js";import{a as X}from"./ping-DI8MvbzV.js";import{c as V}from"./vendor-core-B_fdKJ1g.js";import{P as Y,d as J}from"./payload-decoders-B5IY7u0X.js";import{g as Q,r as Z}from"./system-G149Q__s.js";import{g as ee,K as te,S as re}from"./KeycapButton-BYkRDRdY.js";import{g as ae,B as se,r as ne,T as oe}from"./ascii-burst-CXC_pYgi.js";import{P as ie,B as ce,a as le}from"./PageLayout-DQ0Skliw.js";import{D as de}from"./download-0BKbR_Jq.js";import{S as ue}from"./search-UmBREV7E.js";import{C as pe}from"./chevron-right-CSyaTYjH.js";import"./maplibre-gl-b91ci4Kr.js";import"./keycap-sfx-CAsrNe23.js";const me=u("book-open-text",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M16 12h2",key:"7q9ll5"}],["path",{d:"M16 8h2",key:"msurwy"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}],["path",{d:"M6 12h2",key:"32wvfc"}],["path",{d:"M6 8h2",key:"30oboj"}]]),he=u("corner-down-left",[["path",{d:"M20 4v7a4 4 0 0 1-4 4H4",key:"6o5b7l"}],["path",{d:"m9 10-5 5 5 5",key:"1kshq7"}]]),ge=u("folders",[["path",{d:"M20 5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h2.5a1.5 1.5 0 0 1 1.2.6l.6.8a1.5 1.5 0 0 0 1.2.6z",key:"a4852j"}],["path",{d:"M3 8.268a2 2 0 0 0-1 1.738V19a2 2 0 0 0 2 2h11a2 2 0 0 0 1.732-1",key:"yxbcw3"}]]),fe=u("package",[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]]);class ye{constructor(){t(this,"commands",[])}register(...e){this.commands.push(...e)}find(e){let t;for(const r of this.commands)r.matches(e)&&(!t||r.name.length>t.name.length)&&(t=r);return t}all(){return this.commands}}class xe{constructor(){t(this,"aliases",[]),t(this,"params")}matches(e){const t=e.toLowerCase().trim(),r=e=>t===e||t.startsWith(e+" ");return r(this.name)||this.aliases.some(r)}argsAfterName(e){const t=e.toLowerCase().trim(),r=[this.name,...this.aliases].sort((e,t)=>t.length-e.length);for(const a of r)if(t.startsWith(a))return e.trim().slice(a.length).trim();return e.trim()}}const ve="[",$e=`${ve}0m`,be=`${ve}1m`,we=`${ve}2m`,_e=`${ve}3m`,ke=`${ve}32m`,Ce=`${ve}31m`,Se=`${ve}33m`,je=`${ve}36m`,Ne=`${ve}34m`,Te=`${ve}90m`,Re=`${ve}92m`,Me=`${ve}96m`;function Ee(e,t){switch(t){case"success":return`${ke}${e}${$e}`;case"error":return`${Ce}${e}${$e}`;case"warning":return`${Se}${e}${$e}`;case"info":return`${je}${e}${$e}`;case"value":return`${Ne}${e}${$e}`;case"system":return`${Te}${e}${$e}`;default:return e}}function Ae(e){return`${be}${e}${$e}`}function Ie(e){return`${we}${e}${$e}`}function Fe(e){return`${Ne}${e}${$e}`}function Le(e){return`${Te}${e}${$e}`}function Be(e,t){return`${Te}${e}: ${$e}${Ne}${be}${t}${$e}`}function De(e,t,r=22){const a=e.split(" "),s=a[0];let n=je;return"get"===s?n=ke:"set"===s&&(n=Se),` ${a.length>1?`${n}${be}${s}${$e} ${Ne}${a.slice(1).join(" ")}${$e}`:`${n}${be}${e}${$e}`}${" ".repeat(Math.max(1,r-e.length))}${Te}${t}${$e}`}function Oe(e){return`${be}${Ne}${e}${$e}`}function Pe(e){return`${Te}${_e}${e}${$e}`}function Ue(e){return`${Ce}${be}●${$e} ${Te}${e}${$e}`}function He(e){const t=e<1e3?`${e.toFixed(0)}ms`:`${(e/1e3).toFixed(1)}s`;return`${function(e){return e<1500?Re:e<4e3?ke:e<8e3?Se:e<15e3?Ce:`${Ce}${be}`}(e)}${t}${$e}`}function ze(e){switch(e){case"excellent":return Me;case"good":return ke;case"fair":return Se;case"poor":return Ce;case"critical":return`${Ce}${be}`;default:return Te}}function qe(e,t){return`${ze(t)}${e}${$e}`}function Ke(e){return e.replace(/[\p{Emoji_Presentation}\p{Extended_Pictographic}\uFE0F\u200D]/gu,"").trim()}const We="[2K\r";function Ge(e=1){return`[${e}A`}const Xe="[?1049l",Ve="[?25h";function Ye(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}function Je(e){return Ye(e).length}function Qe(e,t){let r=0;for(const a of e){const e=Ye(a).length;r+=0===e?1:Math.ceil(e/t)}return r}function Ze(e,t){const r=function(e){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()}(e);return r||t}function et(){const e="light"===document.documentElement.dataset.mode,t=Ze("--terminal-bg","#0d0d0d"),r=Ze("--sys-blue",m.blue);if(e){const e="#EFF0F1";return{background:e,foreground:"#111314",cursor:m.blue,cursorAccent:e,selectionBackground:`${m.blue}30`,selectionForeground:"#111314",black:"#111314",red:m.red,green:m.green,yellow:m.amber,blue:m.blue,magenta:m.purple,cyan:m.cyan,white:e,brightBlack:p[500],brightRed:m.red,brightGreen:m.green,brightYellow:m.orange,brightBlue:m.indigo,brightMagenta:m.pink,brightCyan:m.teal,brightWhite:p[600]}}const a=Ze("--text-primary","#e0e0e0"),s=r+"40",n=Ze("--sys-red",m.red),o=Ze("--sys-green",m.green),i=Ze("--sys-purple",m.purple),c=Ze("--sys-blue",m.blue),l=Ze("--sys-cyan",m.cyan),d=Ze("--text-muted",p[500]),u=Ze("--text-secondary",p[400]);return{background:t,foreground:a,cursor:r,cursorAccent:t,selectionBackground:s,selectionForeground:a,black:Ze("--bg-surface",p[900]),red:n,green:o,yellow:i,blue:c,magenta:i,cyan:l,white:a,brightBlack:d,brightRed:n,brightGreen:"#4ADE80",brightYellow:i,brightBlue:c,brightMagenta:i,brightCyan:l,brightWhite:u}}const tt="[",rt=`${tt}0m`,at=`${tt}1m`,st=`${tt}2m`,nt=`${tt}34m`,ot=`${tt}90m`,it=" ",ct=[{label:"INFORMATION",entries:[{cmd:"status",desc:"Repeater status summary",alias:"st"},{cmd:"top",desc:"Live system overview (Ctrl+C to exit)",alias:"htop"},{cmd:"ver",desc:"Version info",alias:"version"},{cmd:"clock",desc:"System UTC time"},{cmd:"uptime",desc:"System uptime"},{cmd:"board",desc:"Board / platform info"},{cmd:"packets",desc:"Packet statistics"},{cmd:"stats-packets",desc:"Packet counters (firmware compat)"},{cmd:"stats-radio",desc:"Radio health stats (firmware compat)"},{cmd:"stats-core",desc:"Engine vitals (firmware compat)"}]},{label:"NETWORK",entries:[{cmd:"neighbors [sort]",desc:"Direct RF neighbors",alias:"nb",sub:"sig · name · rssi · snr · dist · heard"},{cmd:"ping {name}",desc:"Ping neighbor (name or 0xXX)"},{cmd:"identities",desc:"List configured identities",alias:"id ids"},{cmd:"keys",desc:"Transport keys"},{cmd:"acl",desc:"ACL statistics"},{cmd:"rooms",desc:"Room statistics"}]},{label:"RADIO",entries:[{cmd:"get {param}",desc:"Read parameter"},{cmd:"set {param} {value}",desc:"Write parameter"},{cmd:"advert",desc:"Send advertisement"}]},{label:"SYSTEM",entries:[{cmd:"restart",desc:"Restart service",alias:"reboot"},{cmd:"start cap [seconds]",desc:"Start packet capture"},{cmd:"end cap",desc:"Stop capture"},{cmd:"list cap",desc:"List captures"},{cmd:"export cap [id]",desc:"Download capture"}]},{label:"TOOLS",entries:[{cmd:"convert hex {value}",desc:"Hex → base64"},{cmd:"convert base64 {value}",desc:"Base64 → hex"},{cmd:"clear",desc:"Clear terminal",alias:"cls"},{cmd:"help [command]",desc:"Show this help",alias:"? h"}]}],lt=[{cat:"Identity",params:["name","role","lat","lon","public.key"]},{cat:"Radio",params:["radio","freq","tx","bw","sf","cr"]},{cat:"Timing",params:["txdelay","direct.txdelay","rxdelay"]},{cat:"Repeater",params:["mode","duty","repeat","flood.max","advert.interval"]},{cat:"Advanced",params:["multi.acks","int.thresh","agc.reset.interval"]},{cat:"set only",params:["log","prv.key"]}];function dt(e){return`${ot}${"─".repeat(e)}${rt}`}function ut(e){const t=Math.max(3,e-12-8-6);return` ${nt}${at}pymc console${rt} ${dt(t)} ${ot}terminal${rt}`}function pt(e){return` ${ot}${e}${rt}`}function mt(e,t){const r=[],a=e.alias?` ${st}${e.alias}${rt}`:"";return 4+Math.max(e.cmd.length,24)+e.desc.length+(e.alias?2+e.alias.length:0)<=t?r.push(" "+De(e.cmd,e.desc,24)+a):(r.push(" "+De(e.cmd,"",24)),r.push(it+Le(e.desc)+a)),e.sub&&r.push(`${it}${Ie("└ "+e.sub)}`),r}function ht(e){return e.split(" · ").map(e=>`${nt}${e}${rt}`).join(`${ot} · ${rt}`)}function gt(e,t){const r=[];let a=[],s=0;for(const n of e){const e=a.length>0?3+n.length:n.length;s+e>t&&a.length>0?(r.push(a),a=[n],s=n.length):(a.push(n),s+=e)}return a.length>0&&r.push(a),r}function ft(e){const t=["",pt("GET/SET QUALIFIERS")],r=Math.max(20,e-4-13);for(const a of lt){const e=`${ot}${a.cat.padEnd(13)}${rt}`,s=gt(a.params,r),n=" ".repeat(17);t.push(` ${e}${ht(s[0].join(" · "))}`);for(let r=1;r<s.length;r++)t.push(`${n}${ht(s[r].join(" · "))}`)}return t}class yt extends xe{constructor(e){super(),t(this,"name","help"),t(this,"description","Show available commands"),t(this,"aliases",["?","h"]),this.registry=e}execute({output:e,rawInput:t,cols:r}){const a=this.argsAfterName(t).toLowerCase().trim();if(a&&"help"!==a){const t=this.registry.find(a+" help")||this.registry.find(a);return t?void t.execute({output:e,rawInput:t.name+" help",args:[t.name,"help"],cols:r,signal:(new AbortController).signal}):void e.write(`Unknown command: ${Fe(a)}`,"warning")}const s=[ut(r),""];for(const n of ct){s.push(pt(n.label));for(const e of n.entries)s.push(...mt(e,r));"RADIO"===n.label&&s.push(...ft(r)),s.push("")}s.push(...function(e){return[` ${dt(Math.min(e-4,56))}`,` ${Pe("<command> help for detailed usage")}`]}(r)),e.write(s.join("\n"))}}class xt extends xe{constructor(){super(...arguments),t(this,"name","clear"),t(this,"description","Clear terminal screen"),t(this,"aliases",["cls"])}execute({output:e,rawInput:t}){"help"!==this.argsAfterName(t).toLowerCase().trim()?e.clear():e.write([Oe("clear"),` ${Le("Clear all terminal output.")}`,"",De("clear","clear the screen"),"",Oe("Aliases"),` ${Le("cls")}`].join("\n"))}}function vt(e){const t=Math.floor(e/86400),r=Math.floor(e%86400/3600),a=Math.floor(e%3600/60);return t>0?`${t}d ${r}h ${a}m`:r>0?`${r}h ${a}m`:`${a}m`}class $t extends xe{constructor(){super(...arguments),t(this,"name","status"),t(this,"description","Get repeater status summary"),t(this,"aliases",["st"])}async execute({output:e,rawInput:t}){var r,a,s;if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("status"),` ${Le("Show a quick summary of mode, neighbor count, and uptime.")}`,"",De("status","show summary"),"",Oe("Aliases"),` ${Le("st")}`].join("\n"));const n=e.write("processing...","system");try{const t=await g(),o=(null==(a=null==(r=t.config)?void 0:r.repeater)?void 0:a.mode)||"unknown",i=Object.keys(t.neighbors||{}).length,c=Object.values(t.neighbors||{}).filter(e=>e.zero_hop).length,l=(null==(s=t.config)?void 0:s.node_name)||t.node_name||"unknown",d=vt(t.uptime_seconds||0);e.update(n,[`${Ae(l)} ${Le("repeater")}`,"",` ${Be("Mode",Fe(o))}`,` ${Be("Neighbors",`${Fe(String(c))} direct ${Le(`${i} total`)}`)}`,` ${Be("RX / TX",`${Fe(String(t.rx_count??0))} / ${Fe(String(t.tx_count??0))}`)}`,` ${Be("Uptime",Fe(d))}`].join("\n"))}catch(o){e.update(n,`Error: ${o instanceof Error?o.message:"Command failed"}`,"error")}}}class bt extends xe{constructor(){super(...arguments),t(this,"name","uptime"),t(this,"description","Show system uptime")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("uptime"),` ${Le("Display how long the repeater service has been running.")}`,"",De("uptime","show uptime")].join("\n"));const r=e.write("processing...","system");try{const t=await g();e.update(r,Be("Uptime",Fe(vt(t.uptime_seconds||0))))}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}class wt extends xe{constructor(){super(...arguments),t(this,"name","packets"),t(this,"description","Show packet statistics")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("packets"),` ${Le("Display packet counters (received, transmitted, forwarded, dropped).")}`,"",De("packets","show packet stats")].join("\n"));const r=e.write("processing...","system");try{const t=await g(),a=(t.rx_count??0)+(t.tx_count??0);e.update(r,[Oe("Packet Stats")+` ${Le(`${a} total`)}`,"",` ${Be("Received",Fe(String(t.rx_count??0)))}`,` ${Be("Transmitted",Fe(String(t.tx_count??0)))}`,` ${Be("Forwarded",Fe(String(t.forwarded_count??0)))}`,` ${Be("Dropped",Fe(String(t.dropped_count??0)))}`].join("\n"))}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}function _t(e){return e>=1073741824?`${(e/1073741824).toFixed(1)} GB`:e>=1048576?`${(e/1048576).toFixed(0)} MB`:`${(e/1024).toFixed(0)} KB`}function kt(e){const t=Math.floor(e/86400),r=Math.floor(e%86400/3600),a=Math.floor(e%3600/60);return t>0?`${t}d ${r}h ${a}m`:r>0?`${r}h ${a}m`:`${a}m`}class Ct extends xe{constructor(){super(...arguments),t(this,"name","board"),t(this,"description","Show board/platform info")}async execute({output:e,rawInput:t}){var r;if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("board"),` ${Le("Display platform and hardware information.")}`,"",De("board","show board info")].join("\n"));const a=e.write("loading...","system");try{const[t,s]=await Promise.all([f(),g()]),n=[];if(n.push(` ${Be("Node",Fe(s.node_name||"Unknown"))}`),n.push(` ${Be("Runtime",Fe(`pyMC_Repeater v${s.version||"?"}`))}`),s.core_version&&n.push(` ${Be("Core",Fe(s.core_version))}`),n.push(""),t.success&&t.data){const e=t.data;n.push(` ${Be("CPU",Fe(`${e.cpu.usage_percent.toFixed(1)}%`))} ${Le(`${e.cpu.count} core${e.cpu.count>1?"s":""}`)}`),e.cpu.load_avg&&n.push(` ${Be("Load",Fe(`${e.cpu.load_avg["1min"].toFixed(2)} / ${e.cpu.load_avg["5min"].toFixed(2)} / ${e.cpu.load_avg["15min"].toFixed(2)}`))}`);const a=Object.entries(e.temperatures||{});if(a.length>0){const e=a[0];n.push(` ${Be("Temp",Fe(`${e[1].toFixed(1)}°C`))}${a.length>1?` ${Le(a.slice(1).map(([e,t])=>`${e}: ${t.toFixed(1)}°C`).join(", "))}`:""}`)}n.push(""),n.push(` ${Be("Memory",Fe(`${_t(e.memory.used)} / ${_t(e.memory.total)}`))} ${Le(`${e.memory.usage_percent.toFixed(0)}%`)}`),n.push(` ${Be("Disk",Fe(`${_t(e.disk.used)} / ${_t(e.disk.total)}`))} ${Le(`${e.disk.usage_percent.toFixed(0)}%`)}`),n.push(""),(null==(r=e.system)?void 0:r.uptime)&&n.push(` ${Be("System uptime",Fe(kt(e.system.uptime)))}`),n.push(` ${Be("Service uptime",Fe(kt(s.uptime_seconds)))}`),e.network&&n.push(` ${Be("Net TX/RX",Fe(`${_t(e.network.bytes_sent)} / ${_t(e.network.bytes_recv)}`))}`)}else n.push(` ${Be("Platform",Fe("Linux"))}`),n.push(` ${Be("Service uptime",Fe(kt(s.uptime_seconds)))}`),n.push(` ${Le("Hardware stats unavailable")}`);e.update(a,n.join("\n"),"value")}catch(s){e.update(a,`Error: ${s instanceof Error?s.message:"Failed to load hardware stats"}`,"error")}}}const St="[0m",jt="[1m",Nt="[2m",Tt="[36m",Rt="[96m",Mt=48;function Et(e,t,r,a){return s=>{if(s<=0)return 0;if(s>=1)return 1;let n=s;for(let t=0;t<8;t++){const t=3*(1-n)*(1-n)*n*e+3*(1-n)*n*n*r+n*n*n-s,a=3*(1-n)*(1-n)*e+6*(1-n)*n*(r-e)+3*n*n*(1-r);if(Math.abs(a)<1e-7)break;n=Math.max(0,Math.min(1,n-t/a))}return 3*(1-n)*(1-n)*n*t+3*(1-n)*n*n*a+n*n*n}}const At=Et(.25,1,.5,1),It=Et(.4,0,1,1);function Ft(e,t){const r=e%14;return Math.sin(.45*r+.04*r*r+.25*t)}const Lt=[8,16,32,128],Bt=[1,2,4,64].map((e,t)=>e|Lt[t]);function Dt(e,t,r,a){a<4?e[r]|=Bt[a]:t[r]|=Bt[a-4]}function Ot(e){return e>.8?"[97m"+jt:e>.6?"[93m"+jt:e>.4?Rt+jt:e>.2?Rt:e>.08?Tt:Tt+Nt}function Pt(e,t,r){const a=new Uint8Array(Mt),s=new Uint8Array(Mt),n=new Float32Array(Mt),o=.35*e;for(let i=0;i<Mt;i++){const c=r?47-i:i;if(c>=t)continue;const l=t-c,d=Math.min(1,l/3),u=Math.min(1,c/2),p=l<5?1+.3*(1-l/5):1,m=Math.min(1,d*u*p);if(m<.04)continue;const h=1+.06*Math.sin(.7*e+.3*c),g=Ft(c,o)*m*h*3.5+3.5,f=Math.abs(g-3.5)/3.5,y=l<6?1-l/6:0;n[i]=Math.min(1,.65*f+.35*y)*m;const x=Math.max(0,Math.min(7,Math.round(g)));if(g>=3.5){for(let t=3;t<=x;t++)Dt(a,s,i,t);const e=Math.round(.4*(g-3.5));for(let t=Math.max(0,3-e);t<3;t++)Dt(a,s,i,t)}else{for(let t=x;t<=4;t++)Dt(a,s,i,t);const e=Math.round(.4*(3.5-g));for(let t=5;t<=Math.min(7,4+e);t++)Dt(a,s,i,t)}}return{top:a,bot:s,heat:n}}function Ut(e,t,r){const a=new Uint8Array(Mt),s=new Uint8Array(Mt),n=new Float32Array(Mt),o=Math.exp(.5*-t),i=Math.max(0,10-2.5*t),c=.7+.2*t;for(let l=0;l<Math.ceil(i);l++){const t=e?47-l:l;if(t<0||t>=Mt)continue;const d=o*(1-l/i);if(d<.04)continue;n[t]=d;const u=Math.sin(l*c+.6*r)*d*3.5+3.5,p=Math.max(0,Math.min(7,Math.round(u)));if(u>=3.5)for(let e=3;e<=p;e++)Dt(a,s,t,e);else for(let e=p;e<=4;e++)Dt(a,s,t,e)}return{top:a,bot:s,heat:n}}function Ht(e,t){let r="",a="";for(let s=0;s<Mt;s++){const n=String.fromCodePoint(10240+e[s]),o=e[s]?Ot(t[s]):"";o!==a&&(r+=o,a=o),r+=n}return r+St}function zt(e,t,r){const a=e%54;let s,n,o;if(a<22){const t=a/21;({top:s,bot:n,heat:o}=Pt(e,Math.round(At(t)*Mt),!1))}else if(a<27)({top:s,bot:n,heat:o}=Ut(!0,a-22,e));else if(a<49){const t=(a-22-5)/21;({top:s,bot:n,heat:o}=Pt(e,Math.round(It(t)*Mt),!0))}else({top:s,bot:n,heat:o}=Ut(!1,a-22-5-22,e));const i=(r/1e3).toFixed(1),c=`${Nt} ── chirp → ${St}${jt}${t}${St}${Nt} ── ${i}s${St}`;return[Ht(s,o),Ht(n,o),c]}function qt(e,t){const r=Date.now();let a=0;const s=e.write(zt(0,t,0).join("\n")),n=setInterval(()=>{a++,e.update(s,zt(a,t,Date.now()-r).join("\n"))},50);return{id:s,stop:()=>clearInterval(n)}}class Kt extends xe{constructor(){super(...arguments),t(this,"name","advert"),t(this,"description","Send repeater advertisement")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("advert"),` ${Le("Broadcast a repeater advertisement to the mesh network.")}`,"",De("advert","send advert now"),"",Pe("Adverts announce this repeater's presence to neighbors.")].join("\n"));const r=qt(e,"broadcast");try{const t=await y();r.stop(),t.success?e.update(r.id,`✓ ${Fe("Advert sent")}`,"success"):e.update(r.id,`Error: ${t.error||"Failed"}`,"error")}catch(a){r.stop(),e.update(r.id,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}const Wt=["sig","name","rssi","snr","dist","heard"],Gt={excellent:5,good:4,fair:3,poor:2,critical:1};function Xt(e){const t=Math.floor(Date.now()/1e3-e);return t<60?`${t}s ago`:t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:`${Math.floor(t/86400)}d ago`}function Vt(e){return e<1e3?`${Math.round(e)}m`:`${(e/1e3).toFixed(1)}km`}const Yt={excellent:5,good:4,fair:3,poor:2,critical:1};function Jt(e){const t=Yt[e]??0,r=ze(e);return(t>0?`${r}${"█".repeat(t)}${$e}`:"")+Le("⣿".repeat(5-t))}function Qt(e,t=e=>e){return{text:e,color:t}}function Zt(e){return Le("+"+e.map(e=>"-".repeat(e+2)).join("+")+"+")}function er(e,t){const r=e.map((e,r)=>{if(null!=e.rendered){const a=Math.max(0,t[r]-e.text.length);return" "+e.rendered+" ".repeat(a)+" "}return" "+e.color((a=e.text,s=t[r],a.length>=s?a.slice(0,s):a+" ".repeat(s-a.length)))+" ";var a,s});return Le("|")+r.join(Le("|"))+Le("|")}class tr extends xe{constructor(){super(...arguments),t(this,"name","neighbors"),t(this,"description","Show direct RF neighbors with signal stats"),t(this,"aliases",["nb","get neighbors","get neighbor"]),t(this,"params","[sig|name|rssi|snr|dist|heard]")}async execute(e){const{output:t,cols:r}=e,a=this.argsAfterName(e.rawInput).toLowerCase().trim();if("help"===a)return void this.printUsage(t);const s=Wt.includes(a)?a:null,n=t.write("processing...","system");try{const e=await g(),a=e.neighbors||{},o=Object.entries(a).filter(([,e])=>e.zero_hop);if(0===o.length){const e=Object.keys(a).length;return void t.update(n,e>0?`No direct neighbors. ${e} relayed neighbor${1!==e?"s":""} known.`:"No neighbors discovered yet.","warning")}const i=function(e){var t;const r=null==(t=e.config)?void 0:t.radio;return(null==r?void 0:r.spreading_factor)&&(null==r?void 0:r.bandwidth)?{sf:r.spreading_factor,bwHz:r.bandwidth}:null}(e),c=function(e){var t;const r=null==(t=e.config)?void 0:t.repeater;return r&&W(r.latitude,r.longitude)?{lat:r.latitude,lon:r.longitude}:null}(e),l=e.noise_floor_dbm;this.sortNeighbors(o,s,i,c,l);const d=s?` ${Ie(`sorted by ${s}`)}`:"",u=[Oe(`Direct Neighbors (${o.length})`)+d,""];if(r<55)for(const[t,r]of o)u.push(...this.cardLayout(t,r,i,c,l));else{const e=r>=70&&null!=c,t=o.map(([t,r])=>this.buildRow(t,r,i,c,l,e)),a=e?["SIG","NAME","RSSI","SNR","DIST","HEARD"]:["SIG","NAME","RSSI","SNR","HEARD"],s=a.slice(1).map((e,r)=>Math.max(e.length,...t.map(e=>e[r+1].text.length))),n=5,d=s.reduce((e,t)=>e+t+3,0),p=Math.max(4,r-d-n-7),m=[n,Math.min(p,Math.max(4,...t.map(e=>e[1].text.length))),...s.slice(1)];u.push(Zt(m),...t.map(e=>er(e,m)),Zt(m),er(a.map(e=>Qt(e,Ae)),m),Zt(m)),u.push(this.footer(i,l))}t.update(n,u.join("\n"))}catch(o){t.update(n,`Error: ${o instanceof Error?o.message:"Command failed"}`,"error")}}sortNeighbors(e,t,r,a,s){switch(t){case"sig":e.sort(([,e],[,t])=>(Gt[this.gradeNeighbor(e,r,s)]??0)-(Gt[this.gradeNeighbor(t,r,s)]??0));break;case"name":e.sort(([e,t],[r,a])=>{const s=(t.name||t.node_name||e.slice(0,8)).toLowerCase(),n=(a.name||a.node_name||r.slice(0,8)).toLowerCase();return s.localeCompare(n)});break;case"rssi":e.sort(([,e],[,t])=>(e.rssi??-999)-(t.rssi??-999));break;case"snr":e.sort(([,e],[,t])=>(e.snr??-999)-(t.snr??-999));break;case"dist":e.sort(([,e],[,t])=>(this.distTo(e,a)??1/0)-(this.distTo(t,a)??1/0));break;case"heard":e.sort(([,e],[,t])=>(e.last_seen||0)-(t.last_seen||0));break;default:e.sort(([,e],[,t])=>(t.last_seen||0)-(e.last_seen||0))}}gradeNeighbor(e,t,r){const a=null!=e.rssi?e.rssi-3.5:null,s=null!=r&&r>-100?1:0,n=K(e.snr??null,a,t,s);return(null==n?void 0:n.finalGrade)??"critical"}distTo(e,t){return t&&W(e.latitude,e.longitude)?G(t.lat,t.lon,e.latitude,e.longitude):null}buildRow(e,t,r,a,s,n){const o=this.gradeNeighbor(t,r,s),i=Ke(t.name||t.node_name||e.slice(0,8))||e.slice(0,8),c=null!=t.rssi?`${t.rssi} dBm`:"-",l=null!=t.snr?`${t.snr} dB`:"-",d=t.last_seen?Xt(t.last_seen):"-",u=[(p=Jt(o),{text:"|||||",color:e=>e,rendered:p}),Qt(i,Ae),Qt(c,Fe),Qt(l,Fe)];var p;if(n){const e=this.distTo(t,a);u.push(Qt(null!=e?Vt(e):"-",Ie))}return u.push(Qt(d,Ie)),u}cardLayout(e,t,r,a,s){const n=this.gradeNeighbor(t,r,s),o=Ke(t.name||t.node_name||e.slice(0,8))||e.slice(0,8),i=null!=t.rssi?`${t.rssi}`:"-",c=null!=t.snr?`${t.snr}`:"-",l=t.last_seen?Xt(t.last_seen):"-",d=this.distTo(t,a),u=null!=d?` ${Le("dist")} ${Fe(Vt(d))}`:"";return[`${Jt(n)} ${Ae(o)}`,` ${Le("rssi")} ${Fe(i)} ${Le("snr")} ${Fe(c)}${u} ${Ie(l)}`,""]}footer(e,t){const r=[];return e&&r.push(`SF${e.sf}/${e.bwHz>=1e3?e.bwHz/1e3+"kHz":e.bwHz+"Hz"}`),r.push("ant 3.5dBi"),null!=t&&r.push(`nf ${t}dBm`),Le(r.join(" "))}printUsage(e){const t=[Oe("neighbors"),` ${Le("Show direct RF neighbors with signal quality, RSSI, SNR, and distance.")}`,"",Oe("Usage"),De("neighbors","default sort (most recent)"),De("neighbors sig","sort by signal grade (weakest first)"),De("neighbors name","sort alphabetically"),De("neighbors rssi","sort by RSSI (weakest first)"),De("neighbors snr","sort by SNR (lowest first)"),De("neighbors dist","sort by distance (closest first)"),De("neighbors heard","sort by last seen (oldest first)"),De("neighbors help","show this help"),"",Oe("Aliases"),` ${Le("nb, get neighbors, get neighbor")}`,"",Pe("Signal bars factor radio config, noise floor, and 3.5 dBi antenna gain."),Pe("Only zero-hop (direct RF) neighbors are shown.")];e.write(t.join("\n"))}}class rr extends xe{constructor(){super(...arguments),t(this,"name","get"),t(this,"description","Get repeater parameter"),t(this,"params","{parameter}")}async execute({output:e,rawInput:t}){const r=this.argsAfterName(t).toLowerCase().trim();if("help"===r||!r)return void e.write([Oe("get"),` ${Le("Read a repeater configuration parameter.")}`,"",Oe("Identity"),De("get name","node name"),De("get role","node role"),De("get public.key","public key"),"",Oe("Location"),De("get lat","latitude"),De("get lon","longitude"),"",Oe("Radio"),De("get radio","full radio summary"),De("get freq","frequency (MHz)"),De("get tx","TX power (dBm)"),De("get bw","bandwidth (kHz)"),De("get sf","spreading factor"),De("get cr","coding rate"),"",Oe("Timing"),De("get af","airtime factor (pending backend)"),De("get txdelay","TX delay factor"),De("get direct.txdelay","direct TX delay"),De("get rxdelay","RX delay base"),"",Oe("Repeater"),De("get mode","forward or monitor"),De("get flood.max","max flood hops"),De("get advert.interval","advert interval"),De("get duty","duty cycle state"),"",Oe("Advanced"),De("get multi.acks","multi-ack count"),De("get int.thresh","interference threshold (dBm)"),De("get agc.reset.interval","AGC reset interval")].join("\n"));const a=e.write("processing...","system");try{const t=await g(),{result:s,type:n}=function(e,t){const r=t.config||{},a=r.radio||{},s=r.repeater||{},n=r.delays||{},o=r.duty_cycle||{},i=(e,t)=>({result:Be(e,Fe(t)),type:"value"});switch(e){case"name":return i("name",r.node_name||"Unknown");case"role":return i("role","repeater");case"lat":return i("lat",null!=s.latitude?String(s.latitude):"not set");case"lon":return i("lon",null!=s.longitude?String(s.longitude):"not set");case"freq":return i("freq",a.frequency?`${(a.frequency/1e6).toFixed(3)} MHz`:"?");case"tx":return i("tx",null!=a.tx_power?`${a.tx_power} dBm`:"?");case"bw":return i("bw",a.bandwidth?a.bandwidth/1e3+" kHz":"?");case"sf":return i("sf",String(a.spreading_factor??"?"));case"cr":return i("cr",a.coding_rate?`4/${a.coding_rate}`:"?");case"radio":return a.frequency?{result:[` ${Be("freq",Fe(`${(a.frequency/1e6).toFixed(3)} MHz`))}`,` ${Be("bw",Fe(a.bandwidth/1e3+" kHz"))}`,` ${Be("sf",Fe(String(a.spreading_factor)))}`,` ${Be("cr",Fe(`4/${a.coding_rate}`))}`,` ${Be("tx",Fe(`${a.tx_power} dBm`))}`].join("\n"),type:"value"}:i("radio","?");case"af":case"airtime.factor":return{result:`${Le("airtime_factor is not yet exposed by the pyMC_Repeater API.")}\n${Le("Firmware range: 0-9. Controls airtime budget fraction.")}\n${Le("Tracked in CLI-Alignment.md — needs backend support.")}`,type:"warning"};case"txdelay":return i("txdelay",String(n.tx_delay_factor??"1.0"));case"direct.txdelay":return i("direct.txdelay",String(n.direct_tx_delay_factor??"0.5"));case"rxdelay":return i("rxdelay",String(n.rx_delay_base??"0.0"));case"mode":return i("mode",s.mode||"forward");case"repeat":return i("repeat","forward"===s.mode?"on":"off");case"flood.max":return i("flood.max",String(s.max_flood_hops??"3"));case"flood.advert.interval":return i("flood.advert.interval",null!=s.send_advert_interval_hours?`${s.send_advert_interval_hours}h`:"?");case"advert.interval":return i("advert.interval",null!=s.advert_interval_minutes?`${s.advert_interval_minutes}m`:"120m");case"duty":case"duty.enabled":return i("duty",o.enforcement_enabled?"on":"off");case"duty.max":return i("duty.max",null!=o.max_airtime_percent?`${o.max_airtime_percent}%`:"?");case"multi.acks":return i("multi.acks",String(s.multi_acks??"0"));case"int.thresh":return i("int.thresh",`${s.interference_threshold??-120} dBm`);case"agc.reset.interval":return i("agc.reset.interval",String(s.agc_reset_interval??"0"));case"public.key":return i("public.key",t.public_key||"not available");case"prv.key":return{result:`${Le("Private key stored in /etc/pymc_repeater/config.yaml")}\n\n ${Be("view",Fe("sudo grep identity_key /etc/pymc_repeater/config.yaml"))}\n ${Be("set",Fe("sudo ./convert_firmware_key.sh <64-byte-hex>"))}`,type:"info"};case"guest.password":case"allow.read.only":return{result:`${Le("Security settings not exposed via stats API.")}\n${Le("Check /etc/pymc_repeater/config.yaml")}`,type:"warning"};default:return{result:`Unknown parameter: ${Fe(e)}\n${Le('Run "get help" to see available parameters.')}`,type:"error"}}}(r,t);e.update(a,s,n)}catch(s){e.update(a,`Error: ${s instanceof Error?s.message:"Command failed"}`,"error")}}}class ar extends xe{constructor(){super(...arguments),t(this,"name","set"),t(this,"description","Set repeater parameter"),t(this,"params","{parameter} {value}")}async execute({output:e,rawInput:t}){var r;const a=this.argsAfterName(t).split(/\s+/),s=null==(r=a[0])?void 0:r.toLowerCase(),n=a.slice(1).join(" ");if("help"===s||!s)return void e.write([Oe("set"),` ${Le("Write a repeater configuration parameter.")}`,"",Oe("Identity"),De("set name <name>","node name"),De("set lat <deg>","latitude (-90 to 90)"),De("set lon <deg>","longitude (-180 to 180)"),"",Oe("Radio"),De("set freq <MHz>","frequency"),De("set tx <dBm>","TX power (2-22)"),De("set bw <kHz>","bandwidth"),De("set sf <5-12>","spreading factor"),De("set cr <5-8>","coding rate"),"",Oe("Timing"),De("set af <0-9>","airtime factor (pending backend)"),De("set txdelay <0-5>","TX delay factor"),De("set direct.txdelay <0-5>","direct TX delay"),De("set rxdelay <n>","RX delay base"),"",Oe("Repeater"),De("set mode <fwd|mon>","forward or monitor"),De("set flood.max <0-64>","max flood hops"),De("set advert.interval <m>","advert interval (min)"),De("set duty <on|off>","duty cycle enforcement"),De("set log <level>","log level"),"",Oe("Advanced"),De("set multi.acks <n>","multi-ack count"),De("set int.thresh <dBm>","interference threshold"),De("set agc.reset.interval <n>","AGC reset interval (x4)"),"",Pe("Some changes require a service restart.")].join("\n"));const o=e.write("processing...","system");try{const{result:r,type:a}=await async function(e,t,r){switch(e){case"mode":return async function(e){const t=e.toLowerCase();return"forward"!==t&&"monitor"!==t?dr('Mode must be "forward" or "monitor"'):(await b(t)).success?lr(`OK - Mode set to ${t}`):dr("Failed")}(t);case"duty":return async function(e){const t="on"===e.toLowerCase()||"1"===e;return(await $(t)).success?lr("OK - Duty cycle "+(t?"enabled":"disabled")):dr("Failed")}(t);case"tx":return sr("tx_power",or(t,2,22,"TX power must be 2-22 dBm"));case"sf":return sr("spreading_factor",or(t,5,12,"SF must be 5-12"));case"af":case"airtime.factor":return{result:"Error: airtime_factor is not yet exposed by the pyMC_Repeater API.\nFirmware range: 0-9. Tracked in CLI-Alignment.md — needs backend support.",type:"info"};case"txdelay":return sr("tx_delay_factor",ir(t,0,5,"TX delay must be 0.0-5.0"));case"direct.txdelay":return sr("direct_tx_delay_factor",ir(t,0,5,"Direct TX delay must be 0.0-5.0"));case"rxdelay":return sr("rx_delay_base",function(e){const t=parseFloat(e);return isNaN(t)||t<0?{ok:!1,error:"Error: RX delay must be >= 0"}:{ok:!0,value:t}}(t));case"flood.max":return sr("max_flood_hops",or(t,0,64,"Max flood hops must be 0-64"));case"log":return async function(e){const t=e.toUpperCase();if(!["DEBUG","INFO","WARNING","ERROR"].includes(t))return dr("Level must be debug, info, warning, or error");const r=await v(t);return r.success?lr(`OK - Log level set to ${t}`):dr(r.error||"Failed")}(t);case"multi.acks":return sr("multi_acks",or(t,0,255,"Multi-acks must be 0-255"));case"int.thresh":return sr("interference_threshold",or(t,-200,0,"Interference threshold must be -200 to 0 dBm"));case"agc.reset.interval":{const e=cr(t);if(!e.ok)return dr(e.error);if(e.value<0)return dr("AGC reset interval must be >= 0");const r=4*Math.floor(e.value/4);return nr("agc_reset_interval",r,`OK - AGC reset interval set to ${r}${r!==e.value?` (rounded from ${e.value})`:""}`)}case"name":{const e=r.trim().substring(r.toLowerCase().indexOf("name")+5).trim();return e?/[\[\]\\/\\:,?*]/.test(e)?dr("Name contains invalid characters: [ ] \\ / : , ? * are not allowed"):sr("node_name",{ok:!0,value:e}):dr("Node name cannot be empty")}case"lat":return sr("latitude",ir(t,-90,90,"Latitude must be -90 to 90"));case"lon":return sr("longitude",ir(t,-180,180,"Longitude must be -180 to 180"));case"freq":{const e=ir(t,100,1e3,"Frequency must be 100-1000 MHz");return e.ok?sr("frequency",{ok:!0,value:1e6*e.value}):dr(e.error)}case"bw":{const e=[7.8,10.4,15.6,20.8,31.25,41.7,62.5,125,250,500],r=parseFloat(t);return isNaN(r)||!e.includes(r)?dr(`BW must be one of: ${e.join(", ")} kHz`):sr("bandwidth",{ok:!0,value:1e3*r})}case"cr":return sr("coding_rate",or(t,5,8,"Coding rate must be 5-8"));case"advert.interval":{const e=cr(t);return e.ok?0!==e.value&&(e.value<1||e.value>10080)?dr("Advert interval must be 0 (off) or 1-10080 minutes"):nr("advert_interval_minutes",e.value,0===e.value?"OK - Local adverts disabled":`OK - Local advert interval set to ${e.value}m`):dr(e.error)}case"flood.advert.interval":{const e=cr(t);return e.ok?0!==e.value&&(e.value<3||e.value>168)?dr("Flood advert interval must be 0 (off) or 3-168 hours"):nr("flood_advert_interval_hours",e.value,0===e.value?"OK - Flood adverts disabled":`OK - Flood advert interval set to ${e.value}h`):dr(e.error)}case"prv.key":{const e=t.trim();return e?/^[0-9a-fA-F]+$/.test(e)?128!==e.length?dr(`Key must be 64 bytes (128 hex chars), got ${e.length} chars`):{result:`To set this key, run on the Pi:\n\n sudo ./convert_firmware_key.sh ${e}\n\nThen restart: sudo systemctl restart pymc-repeater`,type:"info"}:dr("Private key must be a hex string"):dr("Private key cannot be empty")}default:return dr(`Unknown parameter: ${e}`)}}(s,n,t);e.update(o,r,a)}catch(i){e.update(o,`Error: ${i instanceof Error?i.message:"Command failed"}`,"error")}}}async function sr(e,t){if(!t.ok)return dr(t.error);const r=await x({[e]:t.value});if(!r.success)return dr(r.error||"Failed");let a=`OK - ${e} set to ${t.value}`;return r.restart_required&&(a+="\n⚠ Service restart required for changes to take effect\nRun: sudo systemctl restart pymc_repeater"),lr(a)}async function nr(e,t,r){const a=await x({[e]:t});if(!a.success)return dr(a.error||"Failed");let s=r;return a.restart_required&&(s+="\n⚠ Service restart required for changes to take effect\nRun: sudo systemctl restart pymc_repeater"),lr(s)}function or(e,t,r,a){const s=parseInt(e);return isNaN(s)||s<t||s>r?{ok:!1,error:`Error: ${a}`}:{ok:!0,value:s}}function ir(e,t,r,a){const s=parseFloat(e);return isNaN(s)||s<t||s>r?{ok:!1,error:`Error: ${a}`}:{ok:!0,value:s}}function cr(e){const t=parseInt(e);return isNaN(t)?{ok:!1,error:"Error: Expected a number"}:{ok:!0,value:t}}function lr(e){return{result:e,type:"success"}}function dr(e){return{result:`Error: ${e}`,type:"error"}}const ur={excellent:5,good:4,fair:3,poor:2,critical:1};class pr extends xe{constructor(){super(...arguments),t(this,"name","ping"),t(this,"description","Ping neighbor (name or 0xXX)"),t(this,"params","{target} [timeout]")}async execute({output:e,rawInput:t}){var r,a,s,n;const o=this.argsAfterName(t).trim(),i=o.split(/\s+/);if("help"===(null==(r=i[0])?void 0:r.toLowerCase()))return void e.write([Oe("ping"),` ${Le("Send a ping to a neighbor and measure round-trip time, signal quality, and path.")}`,"",De("ping <name>","ping by node name"),De("ping 0xAB","ping by hex prefix"),De("ping <name> 60","ping with custom timeout (seconds)"),"",Pe("Default timeout: 30s. Signal bars factor radio config and noise floor.")].join("\n"));const c=i[i.length-1],l=parseInt(c),d=i.length>1&&!isNaN(l)&&l>0,u=d?i.slice(0,-1).join(" "):o,p=d?l:30;if(!u)return void e.write([Oe("ping"),` ${Le("Send a ping to a neighbor and measure round-trip time.")}`,"",De("ping <name>","ping by node name"),De("ping <name> 60","with custom timeout"),"",Pe('Run "ping help" for full usage.')].join("\n"));const m=qt(e,u);try{const[t,r]=await Promise.all([X(u,p),g()]);if(m.stop(),t.success&&t.data){const o=t.data,i=null==(a=r.config)?void 0:a.radio,c=(null==i?void 0:i.spreading_factor)&&(null==i?void 0:i.bandwidth)?{sf:i.spreading_factor,bwHz:i.bandwidth}:null,l=r.noise_floor_dbm,d=null!=l&&l>-100?1:0,u=o.rssi-3.5,p=K(o.snr_db,u,c,d),h=(null==p?void 0:p.finalGrade)??"critical",g=function(e){const t=ur[e]??0,r=ze(e);return(t>0?`${r}${"█".repeat(t)}${$e}`:"")+Le("·".repeat(5-t))}(h),f=(null==(s=o.path)?void 0:s.length)?o.path.length:0,y=(null==(n=o.path)?void 0:n.length)?o.path.join(" > "):"direct",x=h.charAt(0).toUpperCase()+h.slice(1),v=[`${g} ${Ae("Reply from")} ${Fe(o.target_id)}`,"",` ${Be("RTT",He(o.rtt_ms))}`,` ${Be("RSSI",`${o.rssi} dBm`)}`,` ${Be("SNR",`${o.snr_db} dB`)}`,` ${Be("Path",y)}${f>0?Le(` (${f} hop${1!==f?"s":""})`):""}`,` ${Be("Quality",qe(x,h))}`],$=[];c&&$.push(`SF${c.sf}/${c.bwHz>=1e3?c.bwHz/1e3+"kHz":c.bwHz+"Hz"}`),$.push("ant 3.5dBi"),null!=l&&$.push(`nf ${l}dBm`),v.push("",Le($.join(" "))),e.update(m.id,v.join("\n"))}else e.update(m.id,t.error||"Ping failed","error")}catch(h){m.stop(),e.update(m.id,`Error: ${h instanceof Error?h.message:"Ping failed"}`,"error")}}}class mr extends xe{constructor(){super(...arguments),t(this,"name","convert"),t(this,"description","Convert between hex and base64"),t(this,"params","hex|base64 {value}")}execute({output:e,args:t}){var r;const a=null==(r=t[1])?void 0:r.toLowerCase(),s=t.slice(2).join(" ").trim();"help"!==a&&(a||s)?"hex"===a?this.hexToBase64(e,s):"base64"===a?this.base64ToHex(e,s):e.write([Oe("convert"),` ${Le("Convert between hex and base64 encodings.")}`,"",De("convert hex <hex>","hex → base64"),De("convert base64 <b64>","base64 → hex")].join("\n")):e.write([Oe("convert"),` ${Le("Convert between hex and base64 encodings.")}`,"",De("convert hex <hex>","hex → base64"),De("convert base64 <b64>","base64 → hex"),"",Pe("Example: convert hex 48656C6C6F")].join("\n"))}hexToBase64(e,t){if(t)if(/^[0-9a-fA-F]+$/.test(t))if(t.length%2==0)try{const r=new Uint8Array(t.length/2);for(let e=0;e<t.length;e+=2)r[e/2]=parseInt(t.substring(e,e+2),16);let a="";const s=8192;for(let e=0;e<r.length;e+=s)a+=String.fromCharCode.apply(null,Array.from(r.subarray(e,Math.min(e+s,r.length))));const n="function"==typeof globalThis.btoa?globalThis.btoa(a):Buffer.from(a,"binary").toString("base64");e.write(` ${Be("hex",Fe(t))}\n ${Be("base64",Fe(n))}`)}catch(r){e.write(`Error: Failed to convert - ${r instanceof Error?r.message:"unknown error"}`,"error")}else e.write("Error: Hex string must have even length","error");else e.write("Error: Input must be a hex string","error");else e.write("Usage: convert hex <hex-string>","error")}base64ToHex(e,t){if(t)try{const r="function"==typeof globalThis.atob?globalThis.atob(t):Buffer.from(t,"base64").toString("binary");let a="";for(let e=0;e<r.length;e++)a+=r.charCodeAt(e).toString(16).padStart(2,"0");e.write(` ${Be("base64",Fe(t))}\n ${Be("hex",Fe(a.toUpperCase()))}`)}catch(r){e.write(`Error: Invalid base64 string - ${r instanceof Error?r.message:"unknown error"}`,"error")}else e.write("Usage: convert base64 <base64-string>","error")}}function hr(){const e=new Date;return`${e.toISOString().slice(0,10)}_${e.toTimeString().slice(0,8).replace(/:/g,"-")}`}function gr(e,t){return`pymc-${e.toISOString().slice(0,10)}-${e.toTimeString().slice(0,5).replace(":","")}-${t}s.json`}const fr=V((e,t)=>({isCapturing:!1,captureStartTime:null,captureStartPacketHashes:new Set,captureTimer:null,reports:[],startCapture:r=>{const{captureTimer:a}=t();a&&clearTimeout(a),e({isCapturing:!0,captureStartTime:new Date,captureStartPacketHashes:new Set(r.map(e=>e.packet_hash))})},stopCapture:r=>{const{isCapturing:a,captureStartTime:s,captureStartPacketHashes:n,captureTimer:o}=t();if(!a||!s)return null;o&&clearTimeout(o);const i=new Date,c=Math.round((i.getTime()-s.getTime())/1e3),l=s.getTime()/1e3,d=r.filter(e=>!n.has(e.packet_hash)&&e.timestamp>=l).sort((e,t)=>e.timestamp-t.timestamp),u={id:hr(),filename:gr(s,c),startTime:s,endTime:i,durationSec:c,packetCount:d.length,packets:d,sizeBytes:500*d.length};return e(e=>({isCapturing:!1,captureStartTime:null,captureStartPacketHashes:new Set,captureTimer:null,reports:[u,...e.reports].slice(0,10)})),u},getReport:e=>t().reports.find(t=>t.id===e),_setTimer:t=>e({captureTimer:t})})),yr=()=>fr(e=>e.reports);function xr(e){var t;return(null==(t=e.match(/.{1,2}/g))?void 0:t.join(" ").toUpperCase())||""}function vr(e){return void 0===e?"UNKNOWN":S[e]??`TYPE_${e}`}function $r(e){return void 0===e?"UNKNOWN":C[e]??`ROUTE_${e}`}function br(e,t){switch(e){case 4:return function(e){const t=[];let r=0;if(e.length>=32&&(t.push({name:"public_key",offset:r,length:32,bytes:xr(k(e.slice(r,r+32))),decoded:{value:k(e.slice(r,r+32))}}),r+=32),e.length>=r+4){const a=e.slice(r,r+4),s=a[0]|a[1]<<8|a[2]<<16|a[3]<<24;t.push({name:"timestamp",offset:r,length:4,bytes:xr(k(a)),decoded:{value:s>>>0,iso:new Date(1e3*s).toISOString()}}),r+=4}if(e.length>=r+64&&(t.push({name:"signature",offset:r,length:64,bytes:xr(k(e.slice(r,r+64))),decoded:{value:k(e.slice(r,r+64))}}),r+=64),e.length>r){const a=e[r],s=[];if(1&a&&s.push("CHAT_NODE"),2&a&&s.push("REPEATER"),3&a&&s.push("ROOM_SERVER"),16&a&&s.push("HAS_LOCATION"),128&a&&s.push("HAS_NAME"),t.push({name:"flags",offset:r,length:1,bytes:xr(k(e.slice(r,r+1))),decoded:{value:a,binary:a.toString(2).padStart(8,"0"),flags:s}}),r+=1,16&a&&e.length>=r+8){const a=e.slice(r,r+8),s=new ArrayBuffer(8);new Uint8Array(s).set(a);const n=new DataView(s),o=n.getInt32(0,!0),i=n.getInt32(4,!0);t.push({name:"location",offset:r,length:8,bytes:xr(k(a)),decoded:{lat_raw:o,lon_raw:i,latitude:o/1e6,longitude:i/1e6}}),r+=8}if(128&a&&e.length>r){const a=e.slice(r);let s=a.indexOf(0);-1===s&&(s=a.length);const n=(new TextDecoder).decode(a.slice(0,s));t.push({name:"name",offset:r,length:s+(0===a[s]?1:0),bytes:xr(k(a.slice(0,s+1))),decoded:{value:n,encoding:"utf-8",null_terminated:0===a[s]}})}}return t}(t);case 3:return function(e){if(e.length<4)return[];const t=e.slice(0,4),r=t[0]|t[1]<<8|t[2]<<16|t[3]<<24;return[{name:"crc",offset:0,length:4,bytes:xr(k(t)),decoded:{value:r>>>0,hex:(r>>>0).toString(16).toUpperCase().padStart(8,"0"),note:"CRC of the acknowledged packet (little-endian)"}}]}(t);case 9:return function(e){const t=[];if(e.length<9)return t;const r=e.slice(0,4),a=r[0]|r[1]<<8|r[2]<<16|r[3]<<24;t.push({name:"trace_tag",offset:0,length:4,bytes:xr(k(r)),decoded:{value:a>>>0,hex:(a>>>0).toString(16).toUpperCase().padStart(8,"0")}});const s=e.slice(4,8),n=s[0]|s[1]<<8|s[2]<<16|s[3]<<24;if(t.push({name:"auth_code",offset:4,length:4,bytes:xr(k(s)),decoded:{value:n>>>0}}),t.push({name:"flags",offset:8,length:1,bytes:xr(k(e.slice(8,9))),decoded:{value:e[8],binary:e[8].toString(2).padStart(8,"0")}}),e.length>9){const r=e.slice(9),a=Array.from(r).map(e=>e.toString(16).toUpperCase().padStart(2,"0"));t.push({name:"target_path",offset:9,length:r.length,bytes:xr(k(r)),decoded:{hops:a,path_string:a.join("->")}})}return t}(t);case 8:return function(e){if(0===e.length)return[];const t=Array.from(e).map(e=>e.toString(16).toUpperCase().padStart(2,"0"));return[{name:"path_hops",offset:0,length:e.length,bytes:xr(k(e)),decoded:{hops:t,path_string:t.join("->")}}]}(t);case 5:return function(e){const t=[];if(e.length<1)return t;if(t.push({name:"channel_hash",offset:0,length:1,bytes:xr(k(e.slice(0,1))),decoded:{value:e[0].toString(16).toUpperCase().padStart(2,"0")}}),e.length>13){const r=12,a=e.length-1-r;t.push({name:"ciphertext",offset:1,length:a,bytes:xr(k(e.slice(1,1+a))),decoded:{length:a,note:"Encrypted message content"}}),t.push({name:"mac",offset:1+a,length:r,bytes:xr(k(e.slice(-r))),decoded:{note:"Message authentication code"}})}return t}(t);default:return function(e){return 0===e.length?[]:[{name:"raw_data",offset:0,length:e.length,bytes:xr(k(e)),decoded:{length:e.length}}]}(t)}}function wr(e){const t=e.type??e.payload_type??0,r=e.route??e.route_type??0,a=e.raw_packet||"";let s,n=null;if(a){const t=Y.fromHex(a);if(t.success&&t.packet){const e=t.packet;try{n=J(e)}catch{n=null}const r=_(a);let o=0;const i={offset:0,length:1,bytes:xr(a.slice(0,2)),decoded:{route_type:e.routeType,route_name:e.routeTypeName,payload_type:e.payloadType,payload_name:e.payloadTypeName,version:e.payloadVersion}};o+=1,e.hasTransportCodes()&&(o+=4);const c={offset:o,length:1,bytes:xr(k(r.slice(o,o+1))),decoded:{value:e.pathLen}};o+=1;const l=o,d=r.slice(o,o+e.pathLen),u=Array.from(e.path).map(e=>e.toString(16).toUpperCase().padStart(2,"0")),p=9===e.payloadType,m={offset:l,length:e.pathLen,bytes:xr(k(d)),decoded:{hops:u,path_string:u.length>0?u.join("->"):"(direct)",...p&&{note:"For TRACE packets, path bytes are SNR×4 values, not node hashes",snr_values:Array.from(e.path).map(e=>{let t=e;return t>127&&(t-=256),t/4})}}};o+=e.pathLen,s={header:i,path_length:c,path:m,payload:{offset:o,length:e.payload.length,bytes:xr(e.payloadHex),sections:br(e.payloadType,e.payload)}}}else s=_r(e)}else s=_r(e);return{timestamp:e.timestamp,packet_hash:e.packet_hash,type:t,type_name:vr(t),route:r,route_name:$r(r),rssi:e.rssi,snr:e.snr,length:e.length??0,src_hash:e.src_hash,dst_hash:e.dst_hash,transmitted:e.transmitted,drop_reason:e.drop_reason,is_duplicate:e.is_duplicate,lbt_attempts:e.lbt_attempts,lbt_backoff_delays_ms:e.lbt_backoff_delays_ms,lbt_channel_busy:e.lbt_channel_busy,raw_packet:a,structure:s,decoded:n}}function _r(e){var t;const r=e.type??e.payload_type??0,a=e.route??e.route_type??0,s=e.original_path??e.forwarded_path??[];return{header:{offset:0,length:1,bytes:"??",decoded:{route_type:a,route_name:$r(a),payload_type:r,payload_name:vr(r),version:0}},path_length:{offset:1,length:1,bytes:s.length.toString(16).toUpperCase().padStart(2,"0"),decoded:{value:s.length}},path:{offset:2,length:s.length,bytes:s.join(" "),decoded:{hops:s,path_string:s.length>0?s.join("->"):"(direct)"}},payload:{offset:2+s.length,length:(null==(t=e.payload)?void 0:t.length)??0,bytes:e.payload??"",sections:e.payload?br(r,_(e.payload)):[]}}}function kr(e,t){const r=function(e,t){var r;return{capture:{start:e.startTime.toISOString(),end:e.endTime.toISOString(),duration_sec:e.durationSec,packet_count:e.packetCount,node_name:(null==t?void 0:t.node_name)??"unknown",local_hash:(null==t?void 0:t.local_hash)??"unknown",pymc_console_version:w,pymc_repeater_version:(null==t?void 0:t.version)??"unknown",radio_config:(null==(r=null==t?void 0:t.config)?void 0:r.radio)?{frequency:t.config.radio.frequency,tx_power:t.config.radio.tx_power,bandwidth:t.config.radio.bandwidth,spreading_factor:t.config.radio.spreading_factor}:null},packets:e.packets.map(wr)}}(e,t),a=JSON.stringify(r,null,2),s=new Blob([a],{type:"application/json"}),n=URL.createObjectURL(s),o=document.createElement("a");o.href=n,o.download=e.filename,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n)}function Cr(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1048576).toFixed(1)} MB`}class Sr extends xe{constructor(){super(...arguments),t(this,"name","cap"),t(this,"description","Packet capture (start/end/list/export)")}matches(e){const t=e.toLowerCase().trim();return"cap"===t||"cap help"===t||t.startsWith("start cap")||t.startsWith("end cap")||t.startsWith("list cap")||t.startsWith("export cap")}async execute({output:e,rawInput:t}){const r=t.toLowerCase().trim();return"cap"===r||"cap help"===r?this.showHelp(e):r.startsWith("start cap")?this.startCapture(e,r):"end cap"===r?this.endCapture(e):"list cap"===r?this.listCaptures(e):r.startsWith("export cap")?this.exportCapture(e,r):void this.showHelp(e)}showHelp(e){const t=fr.getState(),r=t.isCapturing?`\n${Ue('Recording in progress... use "end cap" to stop')}`:"",a=t.reports.length,s=a>0?` (${a} saved)`:"",n=[Oe("Packet Capture"),"",De("start cap","Start capture (default: 120s)"),De("end cap","Stop capture early"),De("list cap",`List saved captures${s}`),De("export cap","Download capture by ID"),"",Pe("Captures stored in session memory. JSON includes decoded payloads."),r].filter(Boolean);e.write(n.join("\n"))}startCapture(e,t){const r=t.slice(9).trim(),a=r?parseInt(r):120;if(isNaN(a)||a<1||a>3600)return void e.write("Error: Duration must be 1-3600 seconds","error");const s=fr.getState();if(s.isCapturing)return void e.write('Error: Capture already in progress. Use "end cap" first.',"error");const n=j.getState().packets;s.startCapture(n);let o=a;const i=e.write(Ue(`Capturing... ${o}s remaining`),"system"),c=setInterval(()=>{o--;const t=fr.getState();if(o>=0&&t.isCapturing){const r=j.getState().packets.filter(e=>{if(!t.captureStartTime)return!1;const r=t.captureStartTime.getTime()/1e3;return e.timestamp>=r&&!t.captureStartPacketHashes.has(e.packet_hash)}).length,a=o>0?`${o}s remaining`:"finishing...";e.update(i,Ue(`Capturing... ${a} (${r} captured)`),"system")}},1e3),l=setTimeout(()=>{clearInterval(c);const t=fr.getState();if(t.isCapturing){const r=j.getState().packets,a=t.stopCapture(r);a?e.write(`✓ Capture complete!\n Captured: ${a.packetCount} packets\n Duration: ${a.durationSec}s\n Size: ~${Cr(a.sizeBytes)}\n\nRun \`export cap ${a.id}\` to download.`,"value"):e.write("Capture completed with no packets.","warning")}},1e3*a);s._setTimer(l)}endCapture(e){const t=fr.getState();if(!t.isCapturing)return void e.write("No capture in progress.","warning");const r=j.getState().packets,a=t.stopCapture(r);a?e.write(`✓ Capture stopped!\n Captured: ${a.packetCount} packets\n Duration: ${a.durationSec}s\n Size: ~${Cr(a.sizeBytes)}\n\nRun \`export cap ${a.id}\` to download.`,"value"):e.write("Capture stopped with no packets.","warning")}listCaptures(e){const{reports:t}=fr.getState();if(0===t.length)return void e.write("No capture reports available.\nStart a capture with: start cap [seconds]","info");const r=t.map((e,t)=>` ${t+1}. ${e.packetCount} pkts • ${e.durationSec}s • ~${Cr(e.sizeBytes)} (id: ${e.id})`);e.write(`Capture Reports (${t.length}):\n${r.join("\n")}`,"info")}exportCapture(e,t){const r=t.slice(10).trim(),a=fr.getState(),s=j.getState().stats;if(!r){if(0===a.reports.length)e.write("No capture reports available.\nStart a capture with: start cap [seconds]","info");else{const t=a.reports.map((e,t)=>` ${t+1}. ${e.id}`);e.write(`Usage: export cap <id>\n\nAvailable reports:\n${t.join("\n")}`,"info")}return}let n=a.getReport(r);if(!n){const e=parseInt(r)-1;n=a.reports[e]}n?(kr(n,s),e.write(`✓ Downloading ${n.filename}...`,"value")):e.write(`Error: Report "${r}" not found.\nUse "list cap" to see available reports.`,"error")}}class jr extends xe{constructor(){super(...arguments),t(this,"name","identities"),t(this,"description","List configured identities"),t(this,"aliases",["id","ids"])}async execute({output:e,rawInput:t}){var r;if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("identities"),` ${Le("List all configured repeater and room server identities.")}`,"",De("identities","list identities"),"",Oe("Aliases"),` ${Le("id, ids")}`].join("\n"));const a=e.write("processing...","system");try{const t=await N();if(!t.success||!t.data)return void e.update(a,t.error||"Failed to fetch identities","error");const s=t.data,n=(null==(r=s.configured)?void 0:r.length)?s.configured:s.registered||[];if(0===n.length)return void e.update(a,"No identities configured.","warning");const o=[Oe(`Identities (${n.length})`),"",...n.map((e,t)=>{var r;const a=e.name||"Unnamed",s=e.type||"unknown",n=(null==(r=e.hash)?void 0:r.slice(0,8))||"—";return` ${Le(`${t+1}.`)} ${Ae(a)} ${Ie(s)} ${Fe(n)}`})];e.update(a,o.join("\n"))}catch(s){e.update(a,`Error: ${s instanceof Error?s.message:"Command failed"}`,"error")}}}class Nr extends xe{constructor(){super(...arguments),t(this,"name","keys"),t(this,"description","List transport keys")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("keys"),` ${Le("List configured transport encryption keys.")}`,"",De("keys","list transport keys")].join("\n"));const r=e.write("processing...","system");try{const t=await Q();if(!t.success||!t.data)return void e.update(r,t.error||"Failed to fetch transport keys","error");const a=t.data;if(0===a.length)return void e.update(r,"No transport keys configured.","warning");const s=[Oe(`Transport Keys (${a.length})`),"",...a.map(e=>{const t=e.parent_id?` ${Ie(`parent: ${e.parent_id}`)}`:"";return` ${Ae(e.name)} ${Be("flood",Fe(e.flood_policy))}${t}`})];e.update(r,s.join("\n"))}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}class Tr extends xe{constructor(){super(...arguments),t(this,"name","acl"),t(this,"description","Show ACL statistics")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("acl"),` ${Le("Display access control list statistics.")}`,"",De("acl","show ACL stats")].join("\n"));const r=e.write("processing...","system");try{const t=await ee();if(!t.success||!t.data)return void e.update(r,t.error||"Failed to fetch ACL stats","error");const a=t.data,s=[Oe("ACL Stats"),"",` ${Be("Identities",Fe(String(a.total_identities)))}`,` ${Be("Total clients",Fe(String(a.total_clients)))}`,` ${Be("Admin",Fe(String(a.admin_clients)))}`,` ${Be("Guest",Fe(String(a.guest_clients)))}`];if(a.by_identity_type){const e=a.by_identity_type.repeater,t=a.by_identity_type.room_server;e&&s.push(` ${Be("Repeater",`${Fe(String(e.count))} ids ${Le(`${e.clients} clients`)}`)}`),t&&s.push(` ${Be("Room Server",`${Fe(String(t.count))} ids ${Le(`${t.clients} clients`)}`)}`)}e.update(r,s.join("\n"))}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}class Rr extends xe{constructor(){super(...arguments),t(this,"name","rooms"),t(this,"description","Show room server statistics")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("rooms"),` ${Le("Display room server statistics and sync status.")}`,"",De("rooms","list rooms")].join("\n"));const r=e.write("processing...","system");try{const t=await T();if(!t.success||!t.data)return void e.update(r,t.error||"Failed to fetch room stats","error");const a=t.data.rooms||[];if(0===a.length)return void e.update(r,"No room servers configured.","warning");const s=[Oe(`Rooms (${a.length})`),"",...a.map(e=>[` ${Ae(e.room_name)}`,` ${Be("msgs",Fe(String(e.total_messages)))} ${Be("clients",`${Fe(String(e.active_clients))}${Ie(`/${e.total_clients}`)}`)} ${Be("sync",e.sync_running?Fe("running"):Ie("idle"))}`]).flat()];e.update(r,s.join("\n"))}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}class Mr extends xe{constructor(){super(...arguments),t(this,"name","restart"),t(this,"description","Restart pymc-repeater service"),t(this,"aliases",["reboot"])}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("restart"),` ${Le("Restart the pymc-repeater systemd service.")}`,"",De("restart","restart the service"),"",Oe("Aliases"),` ${Le("reboot")}`,"",Pe("Requires polkit permissions for the web user."),Pe("The page will need a manual refresh after restart.")].join("\n"));const r=e.write("Restarting service...","system");try{const t=await Z(AbortSignal.timeout(8e3));if(t.success)return e.update(r,"Service restart initiated.","success"),void this.waitForService(e);const a=t.status;if(403===a||401===a)return void e.update(r,"Error: Permission denied.\n\nThe web user needs polkit permissions to restart the service.\nSee: /etc/polkit-1/localauthority/50-local.d/pymc-repeater.pkla","error");e.update(r,t.error||"Restart failed","error")}catch(a){const t=a instanceof Error?a.message:"";t.includes("ERR_NETWORK")||t.includes("ECONNRESET")||t.includes("Failed to fetch")||t.includes("abort")||t.includes("timeout")||a instanceof DOMException&&"TimeoutError"===a.name||a instanceof DOMException&&"AbortError"===a.name?(e.update(r,"Service is restarting (connection dropped).","success"),this.waitForService(e)):e.update(r,`Error: ${t||"Restart failed"}`,"error")}}waitForService(e){const t=e.write("Waiting for service...","system");let r=0,a=!1;setTimeout(()=>{const s=setInterval(async()=>{if(!a){r++,e.update(t,`Waiting for service... ${r}s`,"system");try{await fetch(`${R}/api/stats`,{signal:AbortSignal.timeout(3e3)}),a=!0,clearInterval(s),e.update(t,`Service connected. (${r+4}s)`,"success")}catch{}!a&&r>=30&&(a=!0,clearInterval(s),e.update(t,"Service did not respond within 34s. Check manually.","warning"))}},1e3)},4e3)}}const Er="[",Ar=`${Er}0m`,Ir=`${Er}32m`,Fr=`${Er}33m`,Lr=`${Er}31m`,Br=`${Er}36m`,Dr=`${Er}90m`,Or=`${Er}1m`;function Pr(e){return e>=1073741824?`${(e/1073741824).toFixed(1)}G`:e>=1048576?`${(e/1048576).toFixed(0)}M`:e>=1024?`${(e/1024).toFixed(0)}K`:`${e}B`}function Ur(e){const t=Math.floor(e/86400),r=Math.floor(e%86400/3600),a=Math.floor(e%3600/60);return t>0?`${t}d ${r}h ${a}m`:r>0?`${r}h ${a}m`:`${a}m`}function Hr(e,t){const r=" ".repeat(2),a=t-2,s=[];let n="",o=0;for(const i of e){const e=Je(i);0===o?(n=i,o=e):o+2+e<=a?(n+=" "+i,o+=2+e):(s.push(r+n),n=i,o=e)}return o>0&&s.push(r+n),s}function zr(e,t,r,a,s){if(!e||!t)return` ${Dr}Waiting for data…${Ar}`;const n=function(e,t,r){var a,s;const n=e.node_name||"unknown",o=e.version?`v${e.version}`:"",i=(null==(a=t.system)?void 0:a.uptime)?Ur(t.system.uptime):"?",c=Ur(e.uptime_seconds||0),l=Math.max(3,r-4),d=(null==(s=t.cpu.load_avg)?void 0:s["1min"].toFixed(2))??"?",u=t.cpu.load_avg?`${d} ${t.cpu.load_avg["5min"].toFixed(2)} ${t.cpu.load_avg["15min"].toFixed(2)}`:"?",p=r>=60?u:d;return[` ${Br}${Or}${n}${Ar} ${Dr}${o}${Ar}`,` ${Dr}${"─".repeat(l)}${Ar}`,...Hr([Be("Sys",Fe(i)),Be("Svc",Fe(c)),Be("Load",Fe(p))],r)]}(e,t,a),o=function(e,t){const r=Math.max(6,Math.min(30,t-15)),a=t-(15+r)-2,s=[""],n=`${e.cpu.count} core${e.cpu.count>1?"s":""}`,o=`${Pr(e.memory.used)}/${Pr(e.memory.total)}`,i=`${Pr(e.disk.used)}/${Pr(e.disk.total)}`,c=(e,t,s)=>{const n=function(e,t){const r=Math.max(0,Math.min(100,e)),a=Math.round(r/100*t),s=t-a,n=r>=90?Lr:r>=70?Fr:Ir;return`[${n}${"█".repeat(a)}${Ar}${Dr}${"░".repeat(s)}${Ar}] ${n}${`${r.toFixed(1)}%`.padStart(6)}${Ar}`}(t,r),o=a>=s.length?` ${Ie(s)}`:"";return` ${Le(e.padEnd(4))}${n}${o}`};s.push(c("CPU",e.cpu.usage_percent,n)),s.push(c("Mem",e.memory.usage_percent,o)),s.push(c("Dsk",e.disk.usage_percent,i));const l=Object.entries(e.temperatures||{});if(l.length>0){const e=l.map(([e,t])=>{return`${Ie(e+":")} ${r=t,r>=80?`${Lr}${Or}${r.toFixed(1)}°C${Ar}`:r>=60?`${Fr}${r.toFixed(1)}°C${Ar}`:`${Ir}${r.toFixed(1)}°C${Ar}`}`;var r});s.push(...Hr(e,t))}return s}(t,a),i=function(e,t){var r,a;const s=e.neighbors||{},n=Object.keys(s).length,o=Object.values(s).filter(e=>e.zero_hop).length,i=(null==(a=null==(r=e.config)?void 0:r.repeater)?void 0:a.mode)||"?",c=null!=e.noise_floor_dbm?`${e.noise_floor_dbm}dBm`:"?",l=e.duty_cycle_percent??0,d=["",` ${Dr}MESH${Ar}`];return d.push(...Hr([Be("Mode",Fe(i)),Be("Nbrs",`${Fe(String(o))}${Ie(`/${n}`)}`),Be("Noise",Fe(c)),Be("Air",Fe(`${l.toFixed(1)}%`))],t)),d.push(...Hr([Be("RX",Fe(String(e.rx_count??0))),Be("TX",Fe(String(e.tx_count??0))),Be("FWD",Fe(String(e.forwarded_count??0))),Be("Drop",Fe(String(e.dropped_count??0)))],t)),d.push(...Hr([Be("RX/h",Fe(String(Math.round(e.rx_per_hour??0)))),Be("FWD/h",Fe(String(Math.round(e.forwarded_per_hour??0))))],t)),d}(e,a),c=function(e,t){if(!e.network)return[];const r=["",` ${Dr}NET${Ar}`];return r.push(...Hr([Be("TX",Fe(Pr(e.network.bytes_sent))),Be("RX",Fe(Pr(e.network.bytes_recv))),Be("Pkt",`${Fe(String(e.network.packets_sent))}${Ie("/")}${Fe(String(e.network.packets_recv))}`)],t)),r}(t,a),l=["",` ${Dr}${(new Date).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})} · Ctrl+C to exit${Ar}`],d=[...n,...o,...i,...c,...l],u=s?Qe(d,a):0,p=function(e,t,r){if(0===e.length)return[];const a=t>=50,s=t>=50?6:5,n=t>=50?6:5,o=a?7:0,i=Math.max(4,t-2-o-s-n-4),c=t>=50?8:5,l=null!=r?Math.max(0,Math.min(c,r-3)):c;if(l<=0)return[];const d=["",` ${Dr}PROCS${Ar}`],u=(a?"PID".padEnd(o):"")+"CPU".padStart(s)+"MEM".padStart(n)+" NAME";d.push(` ${Ie(u)}`);for(const p of e.slice(0,l)){const e=a?Ie(String(p.pid).padEnd(o)):"",r=(t>=50?p.cpu_percent.toFixed(1):p.cpu_percent.toFixed(0)).padStart(s),c=(t>=50?p.memory_percent.toFixed(1):p.memory_percent.toFixed(0)).padStart(n),l=p.name.length>i?p.name.slice(0,i-1)+"…":p.name,u=p.cpu_percent>=50?Lr:p.cpu_percent>=20?Fr:"",m=u?`${u}${r}${Ar}`:r;d.push(` ${e}${m}${Ie(c)} ${l}`)}return d}(r,a,s?Math.max(0,s-u):void 0),m=[...d.slice(0,-l.length),...p,...l];return s&&m.length>s&&(m.length=s),m.join("\n")}class qr extends xe{constructor(){super(...arguments),t(this,"name","top"),t(this,"description","Live system overview (Ctrl+C to exit)"),t(this,"aliases",["htop"])}async execute({output:e,rawInput:t,cols:r,signal:a}){var s,n;if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("top"),` ${Le("Live-updating system overview combining hardware")}`,` ${Le("stats, mesh metrics, and running processes.")}`,` ${Le("Refreshes every 3s. Press Ctrl+C to exit.")}`,"",De("top","start live display"),"",Oe("Sections"),` ${Le("Header Node name, version, uptime, load average")}`,` ${Le("Gauges CPU, memory, disk usage with bar charts")}`,` ${Le("Mesh Mode, neighbors, packet counts, airtime")}`,` ${Le("Network TCP/IP bytes and packet counters")}`,` ${Le("Processes Top 8 processes by CPU usage")}`,"",Oe("Aliases"),` ${Le("htop")}`].join("\n"));let o=j.getState().hardwareStats,i=[],c=j.getState().stats;try{const[e,t]=await Promise.all([f(),M()]);e.success&&e.data&&(o=e.data),t.success&&t.data&&(i=t.data.processes.sort((e,t)=>t.cpu_percent-e.cpu_percent))}catch{}if(!a.aborted){null==(s=e.enterFullscreen)||s.call(e);try{const t=e.write(zr(c,o,i,e.cols??r,e.rows));await new Promise(s=>{if(a.aborted)return void s();const n=setInterval(()=>{if(a.aborted)return clearInterval(n),void s();(async()=>{c=j.getState().stats;try{const[e,t]=await Promise.all([f(),M()]);e.success&&e.data&&(o=e.data),t.success&&t.data&&(i=t.data.processes.sort((e,t)=>t.cpu_percent-e.cpu_percent))}catch{}a.aborted||e.update(t,zr(c,o,i,e.cols??r,e.rows))})()},3e3);a.addEventListener("abort",()=>{clearInterval(n),s()},{once:!0})})}finally{null==(n=e.exitFullscreen)||n.call(e)}}}}const Kr=["DONT PANIC","C0FFEE","FEED C0DE","LOL","I CANNOT DO THAT"];function Wr(){return Kr[Math.floor(Math.random()*Kr.length)]}const Gr=new EventTarget,Xr="shell-phrase";function Vr(e){Gr.dispatchEvent(new CustomEvent(Xr,{detail:e??Wr()}))}class Yr extends xe{constructor(){super(...arguments),t(this,"name","fortune"),t(this,"description","Display a fortune on the header"),t(this,"aliases",["lol"])}execute({output:e}){const t=Wr();Vr(t),e.write(Le(` ${t}`))}}const Jr=new EventTarget,Qr="party-time";class Zr extends xe{constructor(){super(...arguments),t(this,"name","partytime"),t(this,"description","Party on, Garth!"),t(this,"aliases",["party","excellent","waynesworld"])}execute({output:e}){Jr.dispatchEvent(new Event(Qr)),Vr("PARTY 0N GARTH"),e.write(Le(" SCHWING!"))}}class ea extends xe{constructor(){super(...arguments),t(this,"name","ver"),t(this,"description","Show version info"),t(this,"aliases",["version"])}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("ver"),` ${Le("Display pyMC_Repeater, core, and console version.")}`,` ${Le('Equivalent to firmware serial CLI "ver" command.')}`,"",De("ver","show version"),"",Oe("Aliases"),` ${Le("version")}`].join("\n"));const r=e.write("processing...","system");try{const t=await g(),a="0.9.276";e.update(r,[` ${Be("pyMC_Repeater",Fe(`v${t.version||"?"}`))}`,` ${Be("pyMC_Core",Fe(t.core_version||"?"))}`,` ${Be("pyMC_Console",Fe(`v${a}`))}`].join("\n"),"value")}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}class ta extends xe{constructor(){super(...arguments),t(this,"name","clock"),t(this,"description","Show system UTC time")}execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("clock"),` ${Le("Display the current system UTC time.")}`,` ${Le('Equivalent to firmware serial CLI "clock" command.')}`,` ${Le("Use to verify NTP sync and correlate packet timestamps.")}`,"",De("clock","show UTC time")].join("\n"));const r=new Date;e.write([` ${Be("UTC",Fe(r.toUTCString()))}`,` ${Be("ISO",Fe(r.toISOString()))}`,` ${Be("Unix",Fe(String(Math.floor(r.getTime()/1e3))))}`].join("\n"),"value")}}class ra extends xe{constructor(){super(...arguments),t(this,"name","stats-packets"),t(this,"description","Packet counters")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("stats-packets"),` ${Le("Display packet counters: sent, received, forwarded, dropped.")}`,` ${Le('Equivalent to firmware serial CLI "stats-packets" command.')}`,"",De("stats-packets","show packet counters")].join("\n"));const r=e.write("processing...","system");try{const t=await g(),a=t.rx_count??0,s=t.tx_count??0,n=t.forwarded_count??0,o=t.dropped_count??0,i=t.rx_per_hour??0,c=t.forwarded_per_hour??0,l=t.duplicate_cache_size??0;e.update(r,[` ${Ae("Packet Counters")}`,"",` ${Be("RX",Fe(String(a)))} ${Le(`${i.toFixed(1)}/hr`)}`,` ${Be("TX",Fe(String(s)))}`,` ${Be("Forwarded",Fe(String(n)))} ${Le(`${c.toFixed(1)}/hr`)}`,` ${Be("Dropped",Fe(String(o)))}`,"",` ${Be("Dup cache",Fe(String(l)))}`].join("\n"),"value")}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}function aa(e){return e>=6e4?`${(e/6e4).toFixed(1)}m`:e>=1e3?`${(e/1e3).toFixed(1)}s`:`${e.toFixed(0)}ms`}class sa extends xe{constructor(){super(...arguments),t(this,"name","stats-radio"),t(this,"description","Radio health stats")}async execute({output:e,rawInput:t}){var r;if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("stats-radio"),` ${Le("Display radio health: airtime, noise floor, duty cycle.")}`,` ${Le('Equivalent to firmware serial CLI "stats-radio" command.')}`,"",De("stats-radio","show radio stats")].join("\n"));const a=e.write("processing...","system");try{const t=await g(),s=null==(r=t.config)?void 0:r.radio,n=t.noise_floor_dbm,o=t.airtime_used_ms??0,i=t.airtime_remaining_ms??0,c=t.duty_cycle_percent??0,l=t.utilization_percent??0,d=t.total_airtime_ms??0,u=[` ${Ae("Radio Stats")}`,""];if(s){const e=s.frequency?`${(s.frequency/1e6).toFixed(3)} MHz`:"?",t=s.bandwidth?s.bandwidth/1e3+" kHz":"?";u.push(` ${Be("Radio",Fe(`${e} SF${s.spreading_factor??"?"} BW ${t} CR 4/${s.coding_rate??"?"} ${s.tx_power??"?"} dBm`))}`),u.push("")}u.push(` ${Be("Noise floor",null!=n?Fe(`${n} dBm`):Le("N/A"))}`),u.push(` ${Be("Airtime used",Fe(aa(o)))} ${Le(`remaining: ${aa(i)}`)}`),u.push(` ${Be("Total airtime",Fe(aa(d)))}`),u.push(` ${Be("Duty cycle",Fe(`${c.toFixed(1)}%`))}`),u.push(` ${Be("Utilization",Fe(`${l.toFixed(1)}%`))}`),e.update(a,u.join("\n"),"value")}catch(s){e.update(a,`Error: ${s instanceof Error?s.message:"Command failed"}`,"error")}}}function na(e){return e>=1073741824?`${(e/1073741824).toFixed(1)} GB`:e>=1048576?`${(e/1048576).toFixed(0)} MB`:`${(e/1024).toFixed(0)} KB`}class oa extends xe{constructor(){super(...arguments),t(this,"name","stats-core"),t(this,"description","Engine vitals")}async execute({output:e,rawInput:t}){if("help"===this.argsAfterName(t).toLowerCase().trim())return void e.write([Oe("stats-core"),` ${Le("Display engine vitals: uptime, memory, CPU, queue depth.")}`,` ${Le('Equivalent to firmware serial CLI "stats-core" command.')}`,` ${Le("On firmware this shows free heap — here we show Linux process health.")}`,"",De("stats-core","show core stats")].join("\n"));const r=e.write("processing...","system");try{const[t,a]=await Promise.all([g(),f()]),s=[` ${Ae("Core Stats")}`,"",` ${Be("Uptime",Fe(vt(t.uptime_seconds??0)))}`,` ${Be("Dup cache",Fe(`${t.duplicate_cache_size??0} entries`))} ${Le(`TTL ${t.cache_ttl??"?"}s`)}`];if(a.success&&a.data){const e=a.data;s.push(""),s.push(` ${Be("CPU",Fe(`${e.cpu.usage_percent.toFixed(1)}%`))} ${Le(`${e.cpu.count} core${e.cpu.count>1?"s":""}`)}`),e.cpu.load_avg&&s.push(` ${Be("Load",Fe(`${e.cpu.load_avg["1min"].toFixed(2)} / ${e.cpu.load_avg["5min"].toFixed(2)} / ${e.cpu.load_avg["15min"].toFixed(2)}`))}`),s.push(` ${Be("Memory",Fe(`${na(e.memory.used)} / ${na(e.memory.total)}`))} ${Le(`${e.memory.usage_percent.toFixed(0)}%`)}`);const t=Object.entries(e.temperatures||{});t.length>0&&s.push(` ${Be("Temp",Fe(`${t[0][1].toFixed(1)}°C`))}`)}e.update(r,s.join("\n"),"value")}catch(a){e.update(r,`Error: ${a instanceof Error?a.message:"Command failed"}`,"error")}}}const ia=["@@@@@@@ @@@ @@@ @@@@@@@@@@ @@@@@@@ ","@@@@@@@@ @@@ @@@ @@@@@@@@@@@ @@@@@@@@ ","@@! @@@ @@! !@@ @@! @@! @@! !@@ ","!@! @!@ !@! @!! !@! !@! !@! !@! ","@!@@!@! !@!@! @!! !!@ @!@ !@! ","!!@!!! @!!! !@! ! !@! !!! ","!!: !!: !!: !!: :!! ",":!: :!: :!: :!: :!: "," :: :: ::: :: ::: ::: "," : : : : :: :: : "],ca=oe-1;class la extends xe{constructor(){super(...arguments),t(this,"name","hello"),t(this,"description","Play the PYMC burst intro"),t(this,"aliases",["hi","intro"])}async execute({output:e,signal:t}){if(t.aborted)return;let r=0;const a=e.write(ae(ia,0).join("\n"));try{await new Promise(s=>{const n=setInterval(()=>{if(t.aborted||r>=ca)return clearInterval(n),t.aborted||e.update(a,ae(ia,ca).join("\n")),void s();r++,e.update(a,ae(ia,r).join("\n"))},se);t.addEventListener("abort",()=>{clearInterval(n),s()},{once:!0})})}finally{ne()}}}const da=V(e=>({entries:[],commandHistory:[],isInitialized:!1,addEntry:t=>{const r="undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}),a={...t,id:r,timestamp:Date.now()};return e(e=>({entries:[...e.entries,a]})),r},updateEntry:(t,r)=>{e(e=>({entries:e.entries.map(e=>e.id===t?{...e,...r}:e)}))},addCommand:t=>{e(e=>({commandHistory:[...e.commandHistory,t]}))},clearEntries:()=>{e({entries:[],commandHistory:[]})},setInitialized:t=>{e({isInitialized:t})}}));function ua({isOpen:e,onClose:t}){const a=yr(),s=j(e=>e.stats);return r.jsxs(E,{open:e,onClose:t,size:"sm",children:[r.jsx(A,{icon:r.jsx(de,{size:20}),title:"Download Captures",onClose:t}),r.jsx(I,{className:"flex flex-col gap-2",children:0===a.length?r.jsxs("div",{className:"flex flex-col items-center gap-2 py-6 text-fg-muted",children:[r.jsx(fe,{className:"w-8 h-8 opacity-40"}),r.jsx("p",{className:"text-sm",children:"No captures available."})]}):a.map(e=>r.jsxs("div",{className:"flex items-center gap-3 px-4 py-3 radius-inset bg-elevated/50 border border-edge-subtle",children:[r.jsxs("div",{className:"flex-1 min-w-0",children:[r.jsx("p",{className:"type-label text-fg-primary truncate",children:e.filename}),r.jsxs("p",{className:"text-xs text-fg-muted mt-0.5",children:[e.packetCount," packets · ",e.durationSec,"s · ~",Cr(e.sizeBytes)]})]}),r.jsx(F,{plain:!0,color:"primary",onClick:()=>(e=>{const t=a.find(t=>t.id===e);t&&kr(t,s)})(e.id),title:"Download",className:"flex-shrink-0",children:r.jsx(de,{"data-slot":"icon"})})]},e.id))})]})}function pa(){const e=yr(),[t,s]=a.useState(!1);return r.jsxs(r.Fragment,{children:[r.jsx(te,{icon:r.jsx(ge,{size:20}),onClick:()=>s(!0),title:e.length>0?`Download captures (${e.length})`:"Captures",variant:"red",iconActiveColor:m.red}),r.jsx(ua,{isOpen:t,onClose:()=>s(!1)})]})}const ma=[{name:"acl",description:"Access control list statistics — identity and client counts.",body:["```","> acl","ACL Stats",""," Identities 2"," Total clients 5"," Admin 2"," Guest 3"," Repeater 1 ids 3 clients"," Room Server 1 ids 2 clients","```"],searchText:"acl access control list statistics identity client"},{name:"advert",description:"Broadcast a repeater advertisement to the mesh.",body:["```","> advert","✓ Advert sent","```"],searchText:"advert advertisement broadcast mesh"},{name:"board",description:"Hardware and platform info — CPU, memory, disk, temperatures, network I/O.",body:["```","> board"," Node Local-Node"," Runtime pyMC_Repeater v1.0.0"," Core v1.12.0",""," CPU 12.3% 4 cores"," Load 0.42 / 0.38 / 0.35"," Temp 48.2°C",""," Memory 412 MB / 664 MB 62%"," Disk 5.2 GB / 28.7 GB 18%",""," System uptime 14d 3h 22m"," Service uptime 2d 14h 32m"," Net TX/RX 128 MB / 342 MB","```"],searchText:"board hardware platform cpu memory disk temperature network"},{name:"cap",description:"Packet capture — start, stop, list, and export captures.",body:["**Sub-commands:** `start cap [sec]` · `end cap` · `list cap` · `export cap [id]`","","**`start cap [seconds]`** — Begin capture (default 120s, max 3600):","```","> start cap","Capturing... 118s remaining (4 captured)","","✓ Capture complete!"," Captured: 23 packets"," Duration: 120s"," Size: ~14.2 KB","```","","**`end cap`** — Stop capture early:","```","> end cap","✓ Capture stopped!"," Captured: 12 packets","```","","**`list cap`** — List saved captures:","```","> list cap","Capture Reports (2):"," 1. 23 pkts • 120s • ~14.2 KB (id: abc123)"," 2. 12 pkts • 34s • ~7.1 KB (id: def456)","```","","**`export cap [id]`** — Download by ID or index:","```","> export cap 1","✓ Downloading capture-abc123.json...","```"],searchText:"cap capture packet start end list export download diagnostic"},{name:"clear",description:"Clear the terminal screen.",body:["**Alias:** `cls`","```","> clear","```"],searchText:"clear cls screen"},{name:"clock",description:"Current system UTC time. Useful for NTP sync and packet timestamp correlation.",body:["```","> clock"," UTC Wed, 12 Feb 2026 00:01:34 GMT"," ISO 2026-02-12T00:01:34.000Z"," Unix 1770768094","```"],searchText:"clock time utc ntp unix iso timestamp"},{name:"convert",description:"Convert between hex and base64 encodings.",body:["**Usage:** `convert hex <value>` · `convert base64 <value>`","```","> convert hex 48656C6C6F"," hex 48656C6C6F"," base64 SGVsbG8=","","> convert base64 SGVsbG8="," base64 SGVsbG8="," hex 48656C6C6F","```"],searchText:"convert hex base64 encoding decode"},{name:"get",description:"Read a configuration parameter.",body:[],interactive:"get",searchText:"get read config parameter name role lat lon radio freq tx bw sf cr txdelay mode duty flood advert"},{name:"help",description:"Show all commands, or detailed help for a specific command.",body:["**Alias:** `?` · `h`","```","> help Full command listing","> help ping Detailed help for ping","> ping help Same thing","```"],searchText:"help commands reference guide"},{name:"identities",description:"List all configured repeater and room server identities.",body:["**Alias:** `id` · `ids`","```","> identities","Identities (2)",""," 1. Local-Node repeater 0A1B2C3D"," 2. local-room room_server 0E5F6A7B","```"],searchText:"identities id ids repeater room server identity"},{name:"keys",description:"List configured transport encryption keys.",body:["```","> keys","Transport Keys (1)",""," main-transport flood: allow","```"],searchText:"keys transport encryption"},{name:"neighbors",description:"Direct RF neighbors with signal quality, RSSI, SNR, distance, and last-heard.",body:["**Alias:** `nb`","","**Sort qualifiers:** `sig` · `name` · `rssi` · `snr` · `dist` · `heard`","```","> neighbors","Direct Neighbors (4)","","+-------+-----------+-----------+--------+-------+--------+","| ▁▃▅▇█ | Node-1 | -87 dBm | 8.5 dB | 2.1km | 3m ago |","| ▁▃▅▇. | Relay-2 | -94 dBm | 5.2 dB | 4.8km | 1m ago |","| ▁▃▅.. | Node-3 | -108 dBm | 1.0 dB | 8.3km | 5m ago |","| ▁▃... | Node-4 | -118 dBm | -3 dB | 14km | 12m ago|","+-------+-----------+-----------+--------+-------+--------+","| SIG | NAME | RSSI | SNR | DIST | HEARD |","+-------+-----------+-----------+--------+-------+--------+","SF11/250kHz ant 3.5dBi nf -112dBm","```","","- **sig** — signal grade (weakest first)","- **name** — alphabetical","- **rssi** — RSSI (weakest first)","- **snr** — SNR (lowest first)","- **dist** — distance (closest first)","- **heard** — last seen (oldest first)"],searchText:"neighbors nb signal rssi snr distance sort direct rf"},{name:"packets",description:"Packet counters — received, transmitted, forwarded, dropped.",body:["```","> packets","Packet Stats 1321 total",""," Received 1284"," Transmitted 37"," Forwarded 891"," Dropped 14","```"],searchText:"packets received transmitted forwarded dropped counter"},{name:"ping",description:"Ping a neighbor by name or hex prefix. Shows RTT, signal quality, and path.",body:["**Usage:** `ping <target> [timeout]`","```","> ping Node-1","▁▃▅▇█ Reply from Node-1",""," RTT 342ms"," RSSI -87 dBm"," SNR 8.5 dB"," Path direct"," Quality Excellent","```","","Custom timeout (default 30s):","```","> ping Node-4 60","```"],searchText:"ping rtt round trip time signal quality path neighbor"},{name:"restart",description:"Restart the pymc-repeater systemd service.",body:["**Alias:** `reboot`","```","> restart","Service is restarting (connection dropped).","Waiting for service... 8s","Service connected. (12s)","```","","The terminal polls automatically until the service comes back up."],searchText:"restart reboot service systemd"},{name:"rooms",description:"Room server statistics — message counts, active clients, sync status.",body:["```","> rooms","Rooms (1)",""," Local Room"," msgs 142 clients 3/5 sync running","```"],searchText:"rooms room server messages clients sync"},{name:"set",description:"Write a configuration parameter.",body:[],interactive:"set",searchText:"set write config parameter name lat lon freq tx bw sf cr txdelay mode duty log flood advert"},{name:"stats-core",description:"Engine vitals — uptime, duplicate cache, CPU, memory, temperature.",body:["```","> stats-core"," Core Stats",""," Uptime 2d 14h 32m"," Dup cache 128 entries TTL 900s",""," CPU 12.3% 4 cores"," Load 0.42 / 0.38 / 0.35"," Memory 412 MB / 664 MB 62%"," Temp 48.2°C","```"],searchText:"stats core engine vitals uptime cache cpu memory temperature"},{name:"stats-packets",description:"Firmware-compatible packet counters with rates and duplicate cache depth.",body:["```","> stats-packets"," Packet Counters",""," RX 1284 22.4/hr"," TX 37"," Forwarded 891 15.2/hr"," Dropped 14",""," Dup cache 128","```"],searchText:"stats packets firmware counter rate duplicate cache"},{name:"stats-radio",description:"Radio health — noise floor, airtime, duty cycle, and radio configuration.",body:["```","> stats-radio"," Radio Stats",""," Radio 906.875 MHz SF11 BW 250 kHz CR 4/5 22 dBm",""," Noise floor -112 dBm"," Airtime used 4.2s remaining: 55.8m"," Total airtime 1.2m"," Duty cycle 1.2%"," Utilization 0.8%","```"],searchText:"stats radio noise floor airtime duty cycle utilization"},{name:"status",description:"Quick summary of mode, neighbors, and uptime.",body:["**Alias:** `st`","```","> status","Local-Node repeater",""," Mode forward"," Neighbors 4 direct 12 total"," RX / TX 1284 / 37"," Uptime 2d 14h 32m","```"],searchText:"status st summary mode neighbors uptime"},{name:"top",description:"Live-updating system overview — CPU/memory gauges, mesh counters, processes.",body:["**Alias:** `htop`","","Refreshes every 3s. Press **Ctrl+C** to exit.","```","> top","Local-Node v1.0.0","──────────────────────────────────"," Sys 14d 3h 22m Svc 2d 14h 32m Load 0.42 0.38 0.35",""," CPU [████░░░░░░░░░░░░] 12.3% 4 cores"," Mem [██████████░░░░░░] 62.1% 412M/664M"," Dsk [███░░░░░░░░░░░░░] 18.4% 5.2G/28.7G"," cpu_thermal: 48.2°C",""," MESH"," Mode forward Nbrs 4/12 Noise -112dBm Air 1.2%"," RX 1284 TX 37 FWD 891 Drop 14"," RX/h 22 FWD/h 15",""," PROCS"," CPU MEM NAME"," 8.2 3.1 python3"," 2.1 1.4 cherrypy",""," 14:32:08 · Ctrl+C to exit","```","","Uses alternate screen buffer — scrollback is preserved."],searchText:"top htop live system overview cpu memory gauges mesh processes"},{name:"uptime",description:"How long the repeater service has been running.",body:["```","> uptime","Uptime 2d 14h 32m","```"],searchText:"uptime service running duration"},{name:"ver",description:"Version info for all three components.",body:["**Alias:** `version`","```","> ver"," pyMC_Repeater v1.0.0"," pyMC_Core v1.12.0"," pyMC_Console v1.0.0","```"],searchText:"ver version pymc repeater core console"}],ha=[{param:"name",category:"Identity",example:["> get name","name Local-Node"]},{param:"role",category:"Identity",example:["> get role","role repeater"]},{param:"lat",category:"Identity",example:["> get lat","lat 34.0522"],range:"-90 to 90"},{param:"lon",category:"Identity",example:["> get lon","lon -118.2437"],range:"-180 to 180"},{param:"public.key",category:"Identity",example:["> get public.key","public.key 0A1B2C3D4E5F..."]},{param:"radio",category:"Radio",example:["> get radio"," freq 906.875 MHz"," bw 250 kHz"," sf 11"," cr 4/5"," tx 22 dBm"]},{param:"freq",category:"Radio",example:["> get freq","freq 906.875 MHz"],range:"100–1000 MHz"},{param:"tx",category:"Radio",example:["> get tx","tx 22 dBm"],range:"2–22 dBm"},{param:"bw",category:"Radio",example:["> get bw","bw 250 kHz"],range:"7.8–500 kHz"},{param:"sf",category:"Radio",example:["> get sf","sf 11"],range:"5–12"},{param:"cr",category:"Radio",example:["> get cr","cr 4/5"],range:"5–8"},{param:"af",category:"Timing",example:["> get af","⚠ airtime_factor not yet exposed by pyMC_Repeater API."," Firmware range: 0-9. Tracked in CLI-Alignment.md."],range:"0–9 (pending)"},{param:"txdelay",category:"Timing",example:["> get txdelay","txdelay 1.0"],range:"0.0–5.0"},{param:"direct.txdelay",category:"Timing",example:["> get direct.txdelay","direct.txdelay 0.5"],range:"0.0–5.0"},{param:"rxdelay",category:"Timing",example:["> get rxdelay","rxdelay 0.0"],range:"≥ 0"},{param:"mode",category:"Repeater",example:["> get mode","mode forward"],range:"forward / monitor"},{param:"duty",category:"Repeater",example:["> get duty","duty on"],range:"on / off"},{param:"flood.max",category:"Repeater",example:["> get flood.max","flood.max 3"],range:"0–64"},{param:"advert.interval",category:"Repeater",example:["> get advert.interval","advert.interval 120m"],range:"0 (off) or 1–10080 min"},{param:"multi.acks",category:"Advanced",example:["> get multi.acks","multi.acks 0"],range:"0–255"},{param:"int.thresh",category:"Advanced",example:["> get int.thresh","int.thresh -120 dBm"],range:"-200 to 0 dBm"},{param:"agc.reset.interval",category:"Advanced",example:["> get agc.reset.interval","agc.reset.interval 0"],range:"≥ 0 (×4)"}],ga=[{param:"name",category:"Identity",example:["> set name Local-Node","OK - node_name set to Local-Node"],range:"text (no [ ] \\ / : , ? *)"},{param:"lat",category:"Identity",example:["> set lat 34.0522","OK - latitude set to 34.0522"],range:"-90 to 90"},{param:"lon",category:"Identity",example:["> set lon -118.2437","OK - longitude set to -118.2437"],range:"-180 to 180"},{param:"freq",category:"Radio",example:["> set freq 906.875","OK - frequency set to 906875000"],range:"100–1000 MHz"},{param:"tx",category:"Radio",example:["> set tx 22","OK - tx_power set to 22"],range:"2–22 dBm"},{param:"bw",category:"Radio",example:["> set bw 250","OK - bandwidth set to 250000"],range:"7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250, 500 kHz"},{param:"sf",category:"Radio",example:["> set sf 11","OK - spreading_factor set to 11"],range:"5–12"},{param:"cr",category:"Radio",example:["> set cr 5","OK - coding_rate set to 5"],range:"5–8"},{param:"af",category:"Timing",example:["> set af 2","⚠ airtime_factor not yet exposed by pyMC_Repeater API."," Firmware range: 0-9. Needs backend support."],range:"0–9 (pending)"},{param:"txdelay",category:"Timing",example:["> set txdelay 1.0","OK - tx_delay_factor set to 1"],range:"0.0–5.0"},{param:"direct.txdelay",category:"Timing",example:["> set direct.txdelay 0.5","OK - direct_tx_delay_factor set to 0.5"],range:"0.0–5.0"},{param:"rxdelay",category:"Timing",example:["> set rxdelay 0","OK - rx_delay_base set to 0"],range:"≥ 0"},{param:"mode",category:"Repeater",example:["> set mode forward","OK - Mode set to forward"],range:"forward / monitor"},{param:"flood.max",category:"Repeater",example:["> set flood.max 3","OK - max_flood_hops set to 3"],range:"0–64"},{param:"advert.interval",category:"Repeater",example:["> set advert.interval 120","OK - Local advert interval set to 120m"],range:"0 (off) or 1–10080 min"},{param:"duty",category:"Repeater",example:["> set duty on","OK - Duty cycle enabled"],range:"on / off"},{param:"log",category:"Repeater",example:["> set log info","OK - Log level set to INFO"],range:"debug, info, warning, error"},{param:"multi.acks",category:"Advanced",example:["> set multi.acks 0","OK - multi_acks set to 0"],range:"0–255"},{param:"int.thresh",category:"Advanced",example:["> set int.thresh -120","OK - interference_threshold set to -120"],range:"-200 to 0 dBm"},{param:"agc.reset.interval",category:"Advanced",example:["> set agc.reset.interval 8","OK - AGC reset interval set to 8"],range:"≥ 0 (rounded to ×4)"},{param:"prv.key",category:"Advanced",example:["> set prv.key <128-hex>","To set this key, run on the Pi:",""," sudo ./convert_firmware_key.sh <key>","","Then restart: sudo systemctl restart pymc-repeater"],range:"128-char hex (SSH only)"}];function fa({mode:e}){const t="get"===e?ha:ga,[s,o]=a.useState(0),i=t[s],c=a.useMemo(()=>{const e=new Map;for(const r of t){const t=e.get(r.category)||[];t.push(r),e.set(r.category,t)}return Array.from(e.entries())},[t]);return r.jsxs("div",{className:"flex flex-col gap-2",children:[r.jsx("div",{className:"flex flex-col gap-1.5",children:c.map(([e,a])=>r.jsxs("div",{className:"flex flex-wrap items-center gap-1",children:[r.jsx("span",{className:"text-xs text-fg-muted w-16 shrink-0 text-right pr-1",children:e}),a.map(e=>{const a=t.indexOf(e),i=a===s;return r.jsx("button",{onClick:()=>o(a),className:n("px-1.5 py-0.5 type-data-xs radius-badge transition-colors cursor-pointer",i?"bg-sys-blue text-fg-invert font-semibold":"bg-elevated text-fg-secondary hover:bg-elevated/80 hover:text-sys-blue"),children:e.param},e.param)})]},e))}),r.jsx("pre",{className:"px-3 py-2.5 radius-inner bg-body text-fg-secondary type-code overflow-x-auto border border-edge-subtle",children:i.example.map((e,t)=>r.jsx("div",{children:e||" "},t))}),i.range&&r.jsxs("p",{className:"text-xs text-fg-muted",children:[r.jsx("span",{className:"text-fg-secondary font-medium",children:i.param})," — ",i.range]})]})}function ya(e,t){const a=e.split(/(\*\*[^*]+\*\*)/g);return r.jsx("span",{children:a.map((e,t)=>e.startsWith("**")&&e.endsWith("**")?r.jsx("strong",{className:"text-fg-primary font-semibold",children:e.slice(2,-2)},t):e.split(/(`[^`]+`)/g).map((e,a)=>e.startsWith("`")&&e.endsWith("`")?r.jsx("code",{className:"px-1 py-0.5 radius-badge bg-elevated text-sys-blue type-data-xs",children:e.slice(1,-1)},`${t}-${a}`):r.jsx("span",{children:e},`${t}-${a}`)))},t)}function xa({lines:e}){const t=[];let a=0;for(;a<e.length;){const s=e[a];if("```"===s){const s=[];for(a++;a<e.length&&"```"!==e[a];)s.push(e[a]),a++;a++,t.push(r.jsx("pre",{className:"px-3 py-2.5 my-2 radius-inner bg-body text-fg-secondary type-code overflow-x-auto border border-edge-subtle",children:s.map((e,t)=>r.jsx("div",{children:e||" "},t))},t.length));continue}s.trim()?s.startsWith("- ")?(t.push(r.jsxs("div",{className:"flex gap-2 text-sm text-fg-secondary pl-2 py-0.5",children:[r.jsx("span",{className:"text-fg-muted shrink-0",children:"•"}),r.jsx("span",{children:ya(s.slice(2),0)})]},t.length)),a++):(t.push(r.jsx("p",{className:"text-sm text-fg-secondary py-0.5",children:ya(s,0)},t.length)),a++):(t.push(r.jsx("div",{className:"h-1.5"},t.length)),a++)}return r.jsx(r.Fragment,{children:t})}function va({isOpen:e,onClose:t,onUseCommand:c}){const[l,d]=a.useState(""),u=a.useMemo(()=>{if(!l.trim())return ma;const e=l.toLowerCase();return ma.filter(t=>t.name.includes(e)||t.searchText.includes(e)||t.description.toLowerCase().includes(e))},[l]),p=l.trim().length>0;return r.jsxs(E,{open:e,onClose:t,size:"3xl",motionPlus:!0,className:"sm:min-w-[540px] md:min-w-[680px]",children:[r.jsx(A,{icon:r.jsx(me,{size:20}),title:"Terminal Command Guide",onClose:t}),r.jsxs(I,{className:"flex flex-col gap-0 !px-0 !py-0",children:[r.jsx("div",{className:"sticky top-0 z-10 px-5 py-3 border-b border-edge-subtle bg-surface/95 backdrop-blur-sm",children:r.jsxs("div",{className:"relative",children:[r.jsx(ue,{size:14,className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-fg-muted"}),r.jsx("input",{type:"text",value:l,onChange:e=>d(e.target.value),placeholder:"Search commands...",className:"w-full pl-8 pr-3 py-1.5 text-sm bg-elevated border border-edge-subtle radius-inner text-fg-primary placeholder:text-fg-muted focus:outline-none focus:ring-1 focus:ring-sys-blue/50",autoFocus:!0})]})}),r.jsxs("div",{className:"overflow-y-auto px-5 py-3 h-[420px] sm:h-[520px] md:h-[600px]",children:[r.jsx(L,{mode:"popLayout",children:0===u.length?r.jsxs(B.div,{initial:{opacity:0,scale:.96},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.96},transition:{duration:O.normal,ease:D.easeOut},className:"flex flex-col items-center gap-2 py-10 text-fg-muted",children:[r.jsx(ue,{className:"w-6 h-6 opacity-40"}),r.jsxs("p",{className:"text-sm",children:['No commands match "',l,'"']})]},"empty"):r.jsx(B.div,{initial:!1,className:"flex flex-col gap-1",children:r.jsx(L,{initial:!1,children:u.map(e=>r.jsx(B.div,{layout:"position",initial:{opacity:0,y:-4},animate:{opacity:1,y:0},exit:{opacity:0,y:-4},transition:P.fade,className:"min-w-0",children:r.jsx(s,{children:({open:t})=>r.jsxs("div",{className:n("radius-inner border transition-colors",t?"border-edge-subtle bg-elevated/50":"border-transparent hover:bg-elevated/30"),children:[r.jsxs("div",{className:"flex items-center w-full min-w-0",children:[r.jsxs(o,{className:"flex items-center gap-3 flex-1 min-w-0 px-3 py-2 text-left cursor-pointer",children:[r.jsx(pe,{size:14,className:n("shrink-0 text-fg-muted transition-transform duration-150",t&&"rotate-90")}),r.jsx("code",{className:"text-sm font-semibold text-sys-blue font-mono shrink-0",children:e.name}),r.jsx("span",{className:"text-xs text-fg-muted truncate min-w-0",children:e.description})]}),c&&r.jsx("button",{onClick:t=>{t.stopPropagation(),c(e.name)},className:"shrink-0 mr-2 px-2 py-0.5 text-xs font-semibold uppercase tracking-wider radius-badge bg-elevated text-fg-muted hover:text-sys-blue hover:bg-elevated/80 transition-colors cursor-pointer",title:`Use "${e.name}" in terminal`,children:"use"})]}),r.jsx(i,{className:"px-3 pb-3 pt-0 pl-9",children:e.interactive?r.jsx(fa,{mode:e.interactive}):r.jsx(xa,{lines:e.body})})]})})},e.name))})},"list")}),r.jsx(L,{children:!p&&r.jsxs(B.div,{initial:{opacity:0,y:6},animate:{opacity:1,y:0},exit:{opacity:0,y:6},transition:{duration:O.normal,ease:D.easeOut},className:"mt-4 px-3 py-3 radius-inner border border-edge-subtle bg-elevated/30",children:[r.jsx("p",{className:"text-xs font-semibold text-fg-muted mb-2",children:"Tips"}),r.jsxs("div",{className:"flex flex-col gap-1 text-xs text-fg-muted",children:[r.jsxs("p",{children:["Type ",r.jsx("code",{className:"px-1 py-0.5 radius-badge bg-elevated text-sys-blue font-mono",children:"<command> help"})," in the terminal for detailed usage."]}),r.jsxs("p",{children:["Most commands have shorter aliases (e.g. ",r.jsx("code",{className:"px-1 py-0.5 radius-badge bg-elevated text-sys-blue font-mono",children:"st"}),", ",r.jsx("code",{className:"px-1 py-0.5 radius-badge bg-elevated text-sys-blue font-mono",children:"nb"}),", ",r.jsx("code",{className:"px-1 py-0.5 radius-badge bg-elevated text-sys-blue font-mono",children:"id"}),")."]}),r.jsxs("p",{children:["Signal bars ",r.jsx("span",{className:"font-mono",children:"▁▃▅▇█"})," are colored by link quality grade based on RSSI, SNR, and radio config."]}),r.jsx("p",{children:"Captures are stored in browser session only — export before closing the tab."})]})]})})]})]})]})}function $a({onUseCommand:e}){const[t,s]=a.useState(!1),n=e?t=>{s(!1),e(t)}:void 0;return r.jsxs(r.Fragment,{children:[r.jsx(te,{icon:r.jsx(me,{size:17,className:"translate-y-px"}),onClick:()=>s(!0),title:"CLI Command Guide"}),r.jsx(va,{isOpen:t,onClose:()=>s(!1),onUseCommand:n})]})}const ba=function(){const e=new ye,t=new yt(e);return e.register(t,new xt,new $t,new ea,new ta,new bt,new wt,new Ct,new ra,new sa,new oa,new Kt,new tr,new pr,new rr,new ar,new mr,new Sr,new jr,new Nr,new Tr,new Rr,new Mr,new qr,new Yr,new Zr,new la),e}(),wa=ba.all().flatMap(e=>[{cmd:e.name,desc:e.description,params:e.params,required:!!e.params},...e.aliases.filter(e=>e.includes(" ")).map(t=>({cmd:t,desc:e.description,params:e.params,required:!!e.params}))]);wa.push({cmd:"start cap",desc:"Start packet capture",params:"[seconds]",required:!0},{cmd:"end cap",desc:"Stop capture"},{cmd:"list cap",desc:"List captures"},{cmd:"export cap",desc:"Download capture",params:"[id]",required:!0});const _a=["sig","name","rssi","snr","dist","heard"],ka={get:["name","role","lat","lon","radio","freq","tx","bw","sf","cr","af","txdelay","direct.txdelay","rxdelay","mode","repeat","flood.max","flood.advert.interval","advert.interval","duty","duty.max","multi.acks","int.thresh","agc.reset.interval","public.key","prv.key"],set:["name","lat","lon","freq","tx","bw","sf","cr","af","txdelay","direct.txdelay","rxdelay","mode","repeat","flood.max","flood.advert.interval","advert.interval","duty","log","multi.acks","int.thresh","agc.reset.interval","prv.key"],convert:["hex","base64"],neighbors:_a,nb:_a,"get neighbors":_a,"get neighbor":_a,"set mode":["forward","monitor"],"set duty":["on","off"],"set repeat":["on","off"],"set tx":["10","14","17","20","22"],"set sf":["7","8","9","10","11","12"],"set bw":["125","250","500"],"set cr":["5","6","7","8"],"set af":["0.5","1.0","1.5","2.0"],"set txdelay":["0.5","0.7","1.0","1.5"],"set direct.txdelay":["0.3","0.5","0.7"],"set log":["debug","info","warning","error"],"start cap":["30","60","120","300"]},Ca=["@@@@@@@ @@@ @@@ @@@@@@@@@@ @@@@@@@ ","@@@@@@@@ @@@ @@@ @@@@@@@@@@@ @@@@@@@@ ","@@! @@@ @@! !@@ @@! @@! @@! !@@ ","!@! @!@ !@! @!! !@! !@! !@! !@! ","@!@@!@! !@!@! @!! !!@ @!@ !@! ","!!@!!! @!!! !@! ! !@! !!! ","!!: !!: !!: !!: :!! ",":!: :!: :!: :!: :!: "," :: :: ::: :: ::: ::: "," : : : : :: :: : "];function Sa(){return/Android|iPhone|iPad|iPod/i.test(navigator.userAgent)||window.innerWidth<640}function ja(){const e=U(),{addCommand:t}=da(),s=a.useRef(null),o=a.useRef(null),i=a.useRef(null),u=a.useRef(null),p=a.useRef(""),m=a.useRef(-1),g=a.useRef(""),f=a.useRef(!1),y=a.useRef(null),x=a.useRef(!1),v=a.useRef(!1),$=a.useRef(!1),b=a.useRef([]),w=a.useRef(()=>{}),_=H(),[k,C]=a.useState("C0dE"),[S,j]=a.useState(!1),N=a.useRef(null),T="C0dE",R=a.useCallback(e=>{N.current&&(clearInterval(N.current),N.current=null);const t=T.padEnd(7),r=t+" "+e+" "+t;let a=0;const s=r.length-7;j(!0),C(r.slice(0,7)),N.current=setInterval(()=>{if(a++,a>s)return clearInterval(N.current),N.current=null,j(!1),void C(T);C(r.slice(a,a+7))},280)},[]);a.useEffect(()=>{const e=function(e){const t=t=>e(t.detail);return Gr.addEventListener(Xr,t),()=>Gr.removeEventListener(Xr,t)}(R),t=setInterval(()=>{Math.random()<.02&&R(Wr())},45e3);return()=>{e(),clearInterval(t),N.current&&clearInterval(N.current)}},[R]);const[M,E]=a.useState(!1),A=a.useRef(null);a.useEffect(()=>{const e=(t=()=>{A.current&&clearTimeout(A.current),E(!0),A.current=setTimeout(()=>E(!1),5e3)},Jr.addEventListener(Qr,t),()=>Jr.removeEventListener(Qr,t));var t;return()=>{e(),A.current&&clearTimeout(A.current)}},[]);const[I,F]=a.useState({show:!1,options:[],selectedIndex:0,input:""}),L=a.useRef([]),B=a.useRef(0);a.useEffect(()=>{(null==e?void 0:e.neighbors)&&(b.current=Object.values(e.neighbors).map(e=>e.node_name||e.name).filter(e=>!!e).sort())},[null==e?void 0:e.neighbors]);const D=a.useCallback(()=>{var e;null==(e=o.current)||e.write(`[1;92m${z()||"user"}@pyMC${$e}: [38;2;91;91;214m$${$e} `)},[]),O=a.useCallback(()=>{const e=o.current;e&&(e.write(We),D(),e.write(p.current))},[D]),P=a.useCallback(e=>{const t=function(e,t){const r=e.toLowerCase(),a=r.trim();if(!a)return[];const s=r.length>a.length&&r.endsWith(" ");if(!a.includes(" ")&&!s)return wa.filter(e=>e.cmd.toLowerCase().startsWith(a));const n=s?a:a.substring(0,a.lastIndexOf(" ")),o=s?"":a.substring(a.lastIndexOf(" ")+1);if("ping"===n&&t.length>0)return t.filter(e=>e.toLowerCase().startsWith(o)).slice(0,10).map(e=>({cmd:`ping ${e}`,desc:`→ ${e}`}));const i=ka[n];if(i){const e=i.filter(e=>e.toLowerCase().startsWith(o)).map(e=>({cmd:`${n} ${e}`,desc:`→ ${e}`}));if(!s&&o){const t=new Set(e.map(e=>e.cmd));for(const r of wa){const s=r.cmd.toLowerCase();s.startsWith(a)&&!t.has(s)&&(e.push(r),t.add(s))}}return e}return wa.filter(e=>e.cmd.toLowerCase().startsWith(a))}(e,b.current);L.current=t,B.current=0;const r=t.length>0&&e.trim().length>0;F({show:r,options:t,selectedIndex:0,input:e.trim()})},[]),K=a.useCallback(()=>{L.current=[],B.current=0,F({show:!1,options:[],selectedIndex:0,input:""})},[]),W=a.useCallback(e=>{var t;const r=L.current[e];r&&(p.current=r.required?r.cmd+" ":r.cmd,O(),r.required?P(p.current):K(),null==(t=o.current)||t.focus())},[O,P,K]),G=a.useCallback(async e=>{const r=o.current;if(!r)return;const a=e.trim();if(!a)return void D();f.current=!0;const s=new AbortController;y.current=s,t(a),m.current=-1;let n=0;const i={get cols(){return r.cols},get rows(){return r.rows},write(e,t="default"){const a=("default"===t?e:Ee(e,t)).split("\n");for(const s of a)r.writeln(s);return n=Qe(a,r.cols),String(n)},update(e,t,a){if($.current)r.write("[H");else if(n>0)for(let o=0;o<n;o++)r.write(Ge()),r.write(We);const s=(a?Ee(t,a):t).split("\n");if($.current){for(const e of s)r.write(e+"[K\r\n");r.write("[J")}else for(const n of s)r.writeln(n);n=Qe(s,r.cols)},clear(){r.clear(),n=0},enterFullscreen(){r.write("[?1049h[?25l"),$.current=!0,n=0},exitFullscreen(){r.write(Ve+Xe),$.current=!1,n=0}};r.writeln("");const c=ba.find(a);if(c){const e=a.split(/\s+/);try{await c.execute({output:i,args:e,rawInput:a,cols:r.cols,signal:s.signal})}catch(l){l instanceof DOMException&&"AbortError"===l.name||i.write(`Error: ${l instanceof Error?l.message:"Command failed"}`,"error")}}else i.write(`Unknown command: ${a}\nType 'help' for available commands.`,"error");y.current=null,f.current=!1,r.writeln(""),D()},[t,D]),X=a.useCallback(e=>{const t=o.current;if(!t)return;if(!v.current)return;if(f.current){for(let r=0;r<e.length;r++)3===e.charCodeAt(r)&&y.current&&(y.current.abort(),t.writeln("^C"));return}const r=da.getState().commandHistory,a=e=>requestAnimationFrame(()=>{var t;return null==(t=document.querySelector(`[data-ac-index="${e}"]`))?void 0:t.scrollIntoView({block:"nearest"})});for(let s=0;s<e.length;s++){const n=e.charCodeAt(s);if(13===n){if(L.current.length>0){const e=L.current[B.current];e&&(p.current=e.cmd,O())}K();const e=p.current;p.current="",t.writeln(""),G(e);continue}if(127!==n&&8!==n)if(3!==n)if(12!==n)if(9!==n)if(27!==n)n>=32&&(p.current+=e[s],t.write(e[s]),m.current=-1,P(p.current));else{if(91===e.charCodeAt(s+1)){const t=e.charCodeAt(s+2);if(s+=2,65===t){if(L.current.length>0){const e=Math.max(B.current-1,0);B.current=e,F(t=>({...t,selectedIndex:e})),a(e)}else r.length>0&&(-1===m.current&&(g.current=p.current),m.current<r.length-1&&(m.current++,p.current=r[r.length-1-m.current]||"",O()));continue}if(66===t){if(L.current.length>0){const e=Math.min(B.current+1,L.current.length-1);B.current=e,F(t=>({...t,selectedIndex:e})),a(e)}else m.current>0?(m.current--,p.current=r[r.length-1-m.current]||"",O()):0===m.current&&(m.current=-1,p.current=g.current,O());continue}if(67===t||68===t)continue;continue}L.current.length>0&&K()}else L.current.length>0&&W(B.current);else t.clear(),K(),O();else p.current="",K(),t.writeln("^C"),D();else p.current.length>0&&(p.current=p.current.slice(0,-1),t.write("\b \b"),P(p.current))}},[K,P,W,D,O,G]);a.useEffect(()=>{w.current=X},[X]);const V=a.useCallback(async()=>{const e=o.current;if(!e||x.current)return;x.current=!0;const t="[94m",r="[0m",a=Ca.length,s=oe-1;try{const t=ae(Ca,0);for(const r of t)e.writeln(r);await new Promise(t=>{let r=0;const n=setInterval(()=>{if(r>=s)return clearInterval(n),void t();r++,e.write(`[${a}F`);const o=ae(Ca,r);for(const t of o)e.write(`[2K${t}\n`)},se)})}finally{ne()}e.writeln(""),e.write(Le("● Initializing terminal...")),await new Promise(e=>setTimeout(e,300)),e.write(We),e.writeln(`${t}✓ Initializing terminal...${r}`),e.write(Le("● Connecting to repeater...")),await new Promise(e=>setTimeout(e,500)),e.write(We),"connected"===q.getState().health?e.writeln(`${t}✓ Connected to repeater${r}`):e.writeln(`${Se}~ Connection status unknown${$e}`),e.writeln(Le("Ready. Type 'help' for commands.")),e.writeln(""),D(),v.current=!0},[D]);a.useEffect(()=>{const e=s.current;if(!e)return;const t=Sa()?12:13,r=new c({theme:et(),fontFamily:'"JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',fontSize:t,lineHeight:Sa()?1.1:.65,cursorBlink:!1,cursorStyle:"underline",scrollback:1e4,convertEol:!0,allowTransparency:!0,rightClickSelectsWord:!1}),a=new l;r.loadAddon(a),r.loadAddon(new d),r.open(e),a.fit(),o.current=r,i.current=a;const n=r.onData(e=>w.current(e)),u=function(e){return h.subscribe(()=>{e.options.theme=et()})}(r),p=new ResizeObserver(()=>{requestAnimationFrame(()=>a.fit())});return p.observe(e),V(),Sa()||r.focus(),()=>{var e;null==(e=y.current)||e.abort(),$.current&&(r.write(Ve+Xe),$.current=!1),n.dispose(),u(),p.disconnect(),r.dispose(),o.current=null,i.current=null}},[]);const Y=a.useCallback(e=>{const t=e.target.value;t.length>0&&(X(t),e.target.value="")},[X]),J=a.useCallback(e=>{"Enter"===e.key?(e.preventDefault(),X("\r")):"Backspace"===e.key?(e.preventDefault(),X("")):"ArrowUp"===e.key?(e.preventDefault(),X("[A")):"ArrowDown"===e.key&&(e.preventDefault(),X("[B"))},[X]),Q=a.useCallback(()=>{var e,t;Sa()?null==(e=u.current)||e.focus():null==(t=o.current)||t.focus()},[]);a.useEffect(()=>{if(!Sa())return;const e=()=>{var e;const t=null==(e=s.current)?void 0:e.querySelector(".xterm-viewport");t&&(t.scrollTop=t.scrollHeight),requestAnimationFrame(()=>{var e;return null==(e=i.current)?void 0:e.fit()})},t=window.visualViewport;if(t){const r=()=>{t.height<.75*window.innerHeight&&e()};return t.addEventListener("resize",r),()=>t.removeEventListener("resize",r)}const r=u.current;if(r){const t=()=>setTimeout(e,300);return r.addEventListener("focus",t),()=>r.removeEventListener("focus",t)}},[]);const Z=a.useCallback(e=>{p.current=e+" ",O(),P(p.current),setTimeout(()=>{var e;null==(e=s.current)||e.click()},400)},[O,P]);return r.jsx(ie,{children:r.jsx(ce,{children:r.jsxs("div",{className:"terminal-card flex flex-col gap-1 sm:gap-1.5",children:[r.jsxs("div",{className:"card-terminal-header flex-wrap",children:[r.jsx("span",{className:"seven-seg-panel",children:r.jsx(re,{text:k,minChars:7,size:24,noCycle:S})}),r.jsx("div",{className:"header-well self-stretch flex-col sm:order-first",children:r.jsxs("div",{className:"indicator-key"+("connected"===_?" indicator-key--active":"degraded"===_?" indicator-key--sending":""),children:[r.jsx("span",{className:"indicator-key__label",children:"ONLINE"}),r.jsx("span",{className:"indicator-key__led"})]})}),r.jsx("div",{className:"card-terminal-ridge flex-1 min-w-4 sm:hidden"}),r.jsxs("div",{className:"header-well flex items-center gap-1 sm:order-last",children:[r.jsx($a,{onUseCommand:Z}),r.jsx(pa,{})]}),r.jsx("div",{className:"card-terminal-ridge flex-1 min-w-8 hidden sm:block"})]}),r.jsx(le,{noPadding:!0,className:"flex flex-col flex-1 min-h-0 overflow-hidden card-terminal",onClick:Q,children:r.jsxs("div",{className:"card-terminal-well flex-1 min-h-0 flex flex-col overflow-hidden",children:[r.jsxs("div",{className:"flex-1 min-h-0 terminal-gutter relative",children:[r.jsx("div",{ref:s,className:"h-full w-full"}),M&&r.jsxs("div",{className:"absolute inset-0 z-10 flex items-center justify-center",onClick:()=>E(!1),children:[r.jsx("div",{className:"absolute inset-0 animate-[partytime-bg_5s_ease-out_forwards]",style:{background:"rgba(0,0,0,0.82)"}}),r.jsxs("div",{className:"relative z-10 animate-[partytime-crt_5s_ease-out_forwards] partytime-glow",children:[r.jsx("img",{src:"/assets/partytime.gif",alt:"No way.",className:"max-h-[60vh] max-w-[70vw] object-contain rounded"}),r.jsx("div",{className:"absolute inset-0 pointer-events-none rounded partytime-scanlines"})]})]})]}),I.show&&I.options.length>0&&r.jsxs("div",{className:"flex-shrink-0 overflow-hidden terminal-completions",style:{borderTop:"1px solid var(--terminal-border)",background:"var(--terminal-bg-input)"},children:[r.jsx("div",{className:"overflow-y-auto",style:{maxHeight:"176px"},children:I.options.map((e,t)=>{const a=t===I.selectedIndex,s=I.input.length;return r.jsxs("div",{"data-ac-index":t,onClick:()=>W(t),className:n("terminal-ac-option",a?"text-sys-blue":"text-fg-primary"),style:{background:a?"var(--terminal-autocomplete-hover)":void 0},onMouseEnter:e=>{a||(e.currentTarget.style.background="var(--terminal-autocomplete-hover)")},onMouseLeave:e=>{a||(e.currentTarget.style.background="")},children:[r.jsx("span",{className:"terminal-ac-option__indicator",children:a?"▸":""}),r.jsxs("span",{className:"terminal-ac-option__cmd",children:[r.jsx("span",{className:"font-semibold text-sys-blue",children:e.cmd.substring(0,s)}),e.cmd.substring(s)]}),r.jsx("span",{className:"terminal-ac-option__desc",children:e.desc})]},e.cmd)})}),r.jsxs("div",{className:"terminal-ac-hints",children:[r.jsx("span",{className:"hidden sm:inline",children:"Tab · ↑↓ · Esc"}),r.jsx("span",{className:"sm:hidden",children:"Tap to select"}),r.jsxs("span",{children:[I.options.length," match",1!==I.options.length?"es":""]})]})]}),r.jsxs("div",{className:"terminal-mobile-input-bar sm:hidden",children:[r.jsx("input",{ref:u,type:"text",className:"terminal-mobile-input",onChange:Y,onKeyDown:J,autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,enterKeyHint:"send","aria-label":"Terminal input",placeholder:"Type command..."}),r.jsx("button",{type:"button",className:"terminal-send-btn",onClick:()=>X("\r"),"aria-label":"Run command",children:r.jsx(he,{})})]}),r.jsxs("div",{className:"terminal-status-bar",children:[r.jsx("span",{className:"hidden sm:inline",children:"↑↓ History · Tab · Esc"}),r.jsx("span",{className:"sm:hidden",children:"Tap input to type"}),(null==e?void 0:e.version)&&r.jsxs("span",{children:["pyMC v",e.version]})]})]})})]})})})}export{ja as default};
|