@h2loop/uav 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/plugins/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{readdir as sn,readFile as on,writeFile as Us,mkdir as Bs}from"fs/promises";import{dirname as Gs,join as H}from"path";import{fileURLToPath as zs}from"url";import{tool as E}from"@kilocode/plugin";import{readdir as zn,readFile as qn}from"fs/promises";import{join as st}from"path";import{open as pn}from"fs/promises";function Be(){let e=process.env.UAV_DECODE_MAX_CPU;if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0&&t<1?t:void 0}var gn=(e)=>new Promise((t)=>setTimeout(t,e));async function Ge(e,t){if(!t||e<=0)return;let r=Math.min(e*(1/t-1),250);if(r>=1)await gn(r)}var ze={a:{kind:"str",width:64},b:{kind:"i8",width:1},B:{kind:"u8",width:1},h:{kind:"i16",width:2},H:{kind:"u16",width:2},i:{kind:"i32",width:4},I:{kind:"u32",width:4},f:{kind:"f32",width:4},d:{kind:"f64",width:8},n:{kind:"str",width:4},N:{kind:"str",width:16},Z:{kind:"str",width:64},c:{kind:"i16",width:2,scale:0.01},C:{kind:"u16",width:2,scale:0.01},e:{kind:"i32",width:4,scale:0.01},E:{kind:"u32",width:4,scale:0.01},L:{kind:"i32",width:4,scale:0.0000001},M:{kind:"u8",width:1},q:{kind:"i64",width:8},Q:{kind:"u64",width:8}};var yn=163,bn=149,_n=128,qe=86;function wn(e){return(t,r)=>{let n="",s=r+e;for(let i=r;i<s;i++){let o=t.getUint8(i);if(o===0)break;n+=String.fromCharCode(o)}return n}}function vn(e){let t=e.scale;switch(e.kind){case"i8":return t===void 0?(r,n)=>r.getInt8(n):(r,n)=>r.getInt8(n)*t;case"u8":return t===void 0?(r,n)=>r.getUint8(n):(r,n)=>r.getUint8(n)*t;case"i16":return t===void 0?(r,n)=>r.getInt16(n,!0):(r,n)=>r.getInt16(n,!0)*t;case"u16":return t===void 0?(r,n)=>r.getUint16(n,!0):(r,n)=>r.getUint16(n,!0)*t;case"i32":return t===void 0?(r,n)=>r.getInt32(n,!0):(r,n)=>r.getInt32(n,!0)*t;case"u32":return t===void 0?(r,n)=>r.getUint32(n,!0):(r,n)=>r.getUint32(n,!0)*t;case"f32":return(r,n)=>r.getFloat32(n,!0);case"f64":return(r,n)=>r.getFloat64(n,!0);case"i64":return(r,n)=>r.getBigInt64(n,!0);case"u64":return(r,n)=>r.getBigUint64(n,!0);case"str":return wn(e.width)}}function Tn(e,t){let r=[],n=[];for(let i of e){let o=ze[i];if(!o)return{readers:[],widths:[],ok:!1,timeIdx:-1};r.push(vn(o)),n.push(o.width)}let s=t.indexOf("TimeUS");return{readers:r,widths:n,ok:!0,timeIdx:s}}async function We(e,t,r){let n=r??Be(),s=new Map,i={},o=!1,a=null,c=null,l=4194304,u=await pn(e,"r");try{let d=Buffer.allocUnsafe(l),f=new Uint8Array(0),m=0,b=!1;while(!b){let{bytesRead:w}=await u.read(d,0,l,m);m+=w,b=w===0;let h;if(w===0)h=f;else if(f.length===0)h=d.subarray(0,w);else h=new Uint8Array(f.length+w),h.set(f,0),h.set(d.subarray(0,w),f.length);let p=new DataView(h.buffer,h.byteOffset,h.byteLength),g=h.length,_=b,v=performance.now(),T=0;while(T+3<=g){if(h[T]!==yn||h[T+1]!==bn){T+=1;continue}let S=h[T+2],x=T+3;if(S===_n){if(x+qe>g){if(_)o=!0;break}let D=h[x],Ue=h[x+1],Q=be(h,x+2,4),ln=be(h,x+6,16),ye=be(h,x+22,64).split(",").filter((hn)=>hn.length>0),{readers:un,widths:dn,ok:fn,timeIdx:mn}=Tn(ln,ye);s.set(D,{name:Q,length:Ue,columns:ye,ok:fn,payloadLen:Ue-3,readers:un,widths:dn,timeIdx:mn}),t.onFmt(Q,ye),i[Q]=(i[Q]??0)+1,T+=3+qe;continue}let M=s.get(S);if(M===void 0){T+=1;continue}let F=M.payloadLen;if(x+F>g){if(_)o=!0;break}if(i[M.name]=(i[M.name]??0)+1,!M.ok){T+=3+F;continue}let{readers:ge,widths:cn}=M,pe=Array(ge.length),je=x;for(let D=0;D<ge.length;D++)pe[D]=ge[D](p,je),je+=cn[D];if(t.onRow(M.name,pe),M.timeIdx>=0){let D=pe[M.timeIdx];if(typeof D==="bigint")c=D}T+=3+F}if(f=h.slice(T),await Ge(performance.now()-v,n),b)break}}finally{await u.close()}if(o)a=c;return{partial:o,decodedUntil:a,messageCounts:i}}function Xe(e,t,r){let n=e[t];if(!n)e[t]={columns:r,rows:[]};else n.columns=r}async function X(e){let t={},r=await We(e,{onFmt:(n,s)=>Xe(t,n,s),onRow:(n,s)=>{t[n].rows.push(s)}});return{partial:r.partial,decodedUntil:r.decodedUntil,tables:t,messageCounts:r.messageCounts}}async function Ke(e,t,r={}){let n=r.retain??new Set,s=5000,i={},o=new Map,a=await We(e,{onFmt:(c,l)=>{if(Xe(i,c,l),t.table(c,l),!o.has(c))o.set(c,[])},onRow:(c,l)=>{let u=o.get(c);if(u){if(u.push(l),u.length>=5000)t.rows(c,u),u.length=0}if(n.has(c))i[c].rows.push(l)}});for(let[c,l]of o)if(l.length)t.rows(c,l);return{partial:a.partial,decodedUntil:a.decodedUntil,tables:i,messageCounts:a.messageCounts}}function be(e,t,r){let n="",s=t+r;for(let i=t;i<s;i++){let o=e[i];if(o===0)break;n+=String.fromCharCode(o)}return n}import{fileURLToPath as An}from"url";var En="no working Python 3 interpreter found. Install Python >= 3.8 and make sure `python3` "+"(macOS/Linux) or `python` (Windows \u2014 tick \u201CAdd python.exe to PATH\u201D in the installer) runs "+"from a terminal, or set UAV_PYTHON to the interpreter's full path.",_e=null,Ye=!1;function Sn(){let e=process.env.UAV_PYTHON?.trim();if(e)return[[e]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function kn(e){try{return await Bun.spawn([...e,"-c","import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"],{stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}async function we(){if(Ye)return _e;for(let e of Sn())if(await kn(e)){_e=e;break}return Ye=!0,_e}async function j(){let e=await we();if(!e)throw Error(En);return e}var Cn=An(new URL("./mavdump.py",import.meta.url)),Rn=new Set(["TimeUS","TimeMS"]);function Je(e){return typeof e==="object"&&e!==null&&"_summary"in e}function Mn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function U(e){let t=await j();if(await Bun.spawn([...t,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore"}).exited!==0)throw Error(`pymavlink not found \u2014 ${t.join(" ")} -m pip install pymavlink`);let n=Bun.spawn([...t,Cn,e],{stdout:"pipe",stderr:"pipe"}),s=new Map,i={},o=!1,a=null,c=null,l=!1;function u(p){let g=s.get(p);if(!g)g={columns:[],colIndex:new Map,rows:[]},s.set(p,g);return g}function d(p){let g=p.t,_=u(g),v=p.f;for(let S of Object.keys(v))if(!_.colIndex.has(S))_.colIndex.set(S,_.columns.length),_.columns.push(S);let T=Array(_.columns.length).fill(null);for(let S of Object.keys(v)){let x=_.colIndex.get(S),M=v[S],F=Rn.has(S)?Mn(M):M;if(T[x]=F,S==="TimeUS"&&typeof F==="bigint")c=F}_.rows.push(T)}let f=new TextDecoder,m="";for await(let p of n.stdout){m+=f.decode(p,{stream:!0});let g;while((g=m.indexOf(`
|
|
3
|
-
`))!==-1){let _=m.slice(0,g);if(m=m.slice(g+1),_.length===0)continue;let v;try{v=JSON.parse(_)}catch{o=!0;continue}if(Je(v)){l=!0;for(let[T,S]of Object.entries(v._summary.counts))i[T]=S;if(v._summary.partial)o=!0}else d(v)}}m+=f.decode();let b=m.trim();if(b.length>0)try{let p=JSON.parse(b);if(Je(p)){l=!0;for(let[g,_]of Object.entries(p._summary.counts))i[g]=_;if(p._summary.partial)o=!0}else d(p)}catch{o=!0}let w=await n.exited;if(w!==0){if(!l){let p=(await new Response(n.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${w})${p?`: ${p}`:""}`)}o=!0}if(!l)o=!0;if(o)a=c;let h={};for(let[p,g]of s)h[p]={columns:g.columns,rows:g.rows};for(let[p,g]of s)if(i[p]===void 0)i[p]=g.rows.length;return{partial:o,decodedUntil:a,tables:h,messageCounts:i}}import{fileURLToPath as $n}from"url";var In=$n(new URL("./ulog.py",import.meta.url)),xn=new Set(["timestamp","timestamp_sample"]);function Fn(e){return typeof e==="object"&&e!==null&&"_summary"in e}function Pn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function Dn(e){let t=()=>Bun.spawn([...e,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore"}).exited;if(await t()===0)return;if(await Bun.spawn([...e,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore"}).exited,await t()!==0)throw Error(`pyulog not found \u2014 ${e.join(" ")} -m pip install pyulog`)}async function Z(e){let t=await j();await Dn(t);let r=Bun.spawn([...t,In,e],{stdout:"pipe",stderr:"pipe"}),n=new Map,s={},i=!1,o=null,a=null,c=!1;function l(p){let g=n.get(p);if(!g)g={columns:[],colIndex:new Map,rows:[]},n.set(p,g);return g}function u(p){let g=p.t,_=l(g),v=p.f;for(let S of Object.keys(v))if(!_.colIndex.has(S))_.colIndex.set(S,_.columns.length),_.columns.push(S);let T=Array(_.columns.length).fill(null);for(let S of Object.keys(v)){let x=_.colIndex.get(S),M=v[S],F=xn.has(S)?Pn(M):M;if(T[x]=F,S==="timestamp"&&typeof F==="bigint")a=F}_.rows.push(T)}function d(p){if(p.length===0)return;let g;try{g=JSON.parse(p)}catch{i=!0;return}if(Fn(g)){c=!0;for(let[_,v]of Object.entries(g._summary.counts))s[_]=v;if(g._summary.partial)i=!0}else u(g)}let f=new TextDecoder,m="";for await(let p of r.stdout){m+=f.decode(p,{stream:!0});let g;while((g=m.indexOf(`
|
|
4
|
-
`))!==-1)d(m.slice(0,g)),m=m.slice(g+1)}m+=f.decode();let b=m.trim();if(b.length>0)d(b);let w=await r.exited;if(w!==0){if(!c){let p=(await new Response(r.stderr).text()).trim();throw Error(`ulog decode failed (exit ${w})${p?`: ${p}`:""}`)}i=!0}if(!c)i=!0;if(i)o=a;let h={};for(let[p,g]of n)h[p]={columns:g.columns,rows:g.rows};for(let[p,g]of n)if(s[p]===void 0)s[p]=g.rows.length;return{partial:i,decodedUntil:o,tables:h,messageCounts:s}}import{existsSync as Qe,readFileSync as Nn}from"fs";import{mkdtemp as Ln,rm as On}from"fs/promises";import{tmpdir as Hn}from"os";import{basename as ve,join as Te}from"path";function ee(e){if(!e)return[];let t=Te(e,".hydron","uav-format-converters.json");if(!Qe(t))return[];try{let r=JSON.parse(Nn(t,"utf8"));return Array.isArray(r.converters)?r.converters.filter((n)=>n&&n.match&&n.command):[]}catch{return[]}}function te(e,t){for(let r of t)try{if(new RegExp(r.match,"i").test(e))return r}catch{}return null}async function ne(e,t){let r=await Ln(Te(Hn(),"uav-convert-")),n=ve(e).replace(/\.[^.]+$/,""),s=Te(r,n+(t.produces??".bin")),i=t.command.replaceAll("{input}",e).replaceAll("{output}",s),o=()=>On(r,{recursive:!0,force:!0});try{let a=process.platform==="win32"?["cmd.exe","/d","/s","/c",i]:["bash","-lc",i],c=Bun.spawn(a,{stdout:"pipe",stderr:"pipe"}),l=await c.exited;if(l!==0){let u=(await new Response(c.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${l}) for ${ve(e)}: ${u}`)}if(!Qe(s))throw Error(`format converter produced no output for ${ve(e)}`);return{out:s,cleanup:o}}catch(a){throw await o(),a}}import{Database as Vn}from"bun:sqlite";import{tmpdir as jn}from"os";import{join as Un}from"path";import{existsSync as Ze,unlinkSync as et}from"fs";var Bn=0;function nt(e){let t=Un(jn(),`uav-${e}-${process.pid}-${Bn++}.sqlite`);try{if(Ze(t))et(t)}catch{}let r=new Vn(t);return r.exec("PRAGMA page_size = 8192"),r.query("PRAGMA journal_mode = MEMORY").get(),r.exec("PRAGMA synchronous = OFF"),r.exec("PRAGMA temp_store = FILE"),r.exec("PRAGMA cache_size = -65536"),{db:r,cleanup(){try{r.close()}catch{}try{if(Ze(t))et(t)}catch{}}}}var Ee=(e)=>`"${e.replace(/"/g,'""')}"`,tt=5000;function Se(e){let t=new Map,r=new Map;return{table(n,s){if(t.has(n)||s.length===0)return;e.run(`CREATE TABLE ${Ee(n)} (${s.map(Ee).join(", ")})`);let i=s.map(()=>"?").join(", ");t.set(n,e.query(`INSERT INTO ${Ee(n)} VALUES (${i})`)),r.set(n,s.length)},rows(n,s){let i=t.get(n),o=r.get(n);if(!i||o===void 0||s.length===0)return;let a=e.transaction((c)=>{for(let l of c){let u=Array(o);for(let d=0;d<o;d++){let f=l[d];u[d]=f===void 0?null:f}i.run(...u)}});for(let c=0;c<s.length;c+=tt)a(s.slice(c,c+tt))}}}function rt(e,t){let r=Se(e);for(let[n,s]of Object.entries(t.tables)){if(s.columns.length===0)continue;if(r.table(n,s.columns),s.rows.length)r.rows(n,s.rows)}}var Gn=new Set(["PARM","MSG","GPS","ERR","MODE"]);async function K(e,t="flight",r){let n=te(e,ee(r?.configDir));if(n){let{out:o,cleanup:a}=await ne(e,n);try{return await K(o,t)}finally{await a()}}let{db:s,cleanup:i}=nt(t);try{let o=e.toLowerCase();if(o.endsWith(".bin"))return{log:await Ke(e,Se(s),{retain:Gn}),db:s,cleanup:i};let a;if(o.endsWith(".ulog"))a=await Z(e);else if(o.endsWith(".tlog")||o.endsWith(".log"))a=await U(e);else try{a=await X(e)}catch{a=await U(e)}return rt(s,a),{log:a,db:s,cleanup:i}}catch(o){throw i(),o}}var re=1e4;async function Wn(e,t,r){let n=st(e,".hydron","observations",t),s;try{s=await zn(n)}catch{throw Error(`No observation store at ${n}. Run uav_analyze first.`)}for(let i of s){let o=st(n,i,`${r}.json`);try{let c=JSON.parse(await qn(o,"utf8"))?.episode?.attrs?.source_path;if(typeof c==="string"&&c)return c;throw Error(`Episode ${r} has no source_path; re-run uav_analyze to record it.`)}catch(a){if(a.code==="ENOENT")continue;throw a}}throw Error(`flight_id ${r} not found in the observation store. Run uav_analyze first.`)}function Xn(e){let t=e.trim();t=t.replace(/^```(?:sql)?\s*/i,"").replace(/\s*```$/,"").trim();for(;;){let s=t;if(t=t.replace(/^--[^\n]*\n?/,"").replace(/^\/\*[\s\S]*?\*\//,"").trimStart(),t===s)break}if(t=t.replace(/;\s*$/,""),t.includes(";"))throw Error("Only a single statement is allowed (no ';').");let r=t.replace(/^\(+\s*/,"");if(!(/^\s*(select|with|values)\b/i.test(r)||/^\s*explain\b/i.test(t)||/^\s*pragma\s+(table_info|table_list|table_xinfo|index_list|index_info|index_xinfo|database_list|collation_list|function_list|pragma_list)\b/i.test(t)))throw Error("uav_query is read-only: use SELECT/WITH/VALUES (comments & ```fences ok), EXPLAIN, or a read PRAGMA (table_info/table_list/index_*). For heavier analysis use Python via bash, not SQL.");if(/\b(insert|update|delete|drop|create|alter|attach|detach|replace|reindex|vacuum)\b/i.test(t))throw Error("Write/DDL keyword detected \u2014 uav_query is read-only.");if(!/\blimit\b/i.test(t))t+=` LIMIT ${re}`;return t}async function it(e){let t=Xn(e.query),r=await Wn(e.projectDir,e.workspace,e.flight_id),{db:n,cleanup:s}=await K(r,e.flight_id);try{n.exec?.("PRAGMA query_only = ON");let o=n.query(t).all(),a=o.length?Object.keys(o[0]):[],l=o.slice(0,re).map((u)=>a.map((d)=>u[d]));return{columns:a,rows:l,truncated:o.length>re}}finally{s()}}function ot(e){if(!e.columns.length)return"(no rows)";let t=e.columns.join(" | "),r=e.rows.slice(0,50).map((s)=>s.map((i)=>typeof i==="bigint"?i.toString():String(i)).join(" | ")).join(`
|
|
2
|
+
import{readdir as sn,readFile as on,writeFile as Us,mkdir as Bs}from"fs/promises";import{dirname as Gs,join as H}from"path";import{fileURLToPath as zs}from"url";import{tool as E}from"@kilocode/plugin";import{readdir as zn,readFile as qn}from"fs/promises";import{join as st}from"path";import{open as pn}from"fs/promises";function Be(){let e=process.env.UAV_DECODE_MAX_CPU;if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0&&t<1?t:void 0}var gn=(e)=>new Promise((t)=>setTimeout(t,e));async function Ge(e,t){if(!t||e<=0)return;let r=Math.min(e*(1/t-1),250);if(r>=1)await gn(r)}var ze={a:{kind:"str",width:64},b:{kind:"i8",width:1},B:{kind:"u8",width:1},h:{kind:"i16",width:2},H:{kind:"u16",width:2},i:{kind:"i32",width:4},I:{kind:"u32",width:4},f:{kind:"f32",width:4},d:{kind:"f64",width:8},n:{kind:"str",width:4},N:{kind:"str",width:16},Z:{kind:"str",width:64},c:{kind:"i16",width:2,scale:0.01},C:{kind:"u16",width:2,scale:0.01},e:{kind:"i32",width:4,scale:0.01},E:{kind:"u32",width:4,scale:0.01},L:{kind:"i32",width:4,scale:0.0000001},M:{kind:"u8",width:1},q:{kind:"i64",width:8},Q:{kind:"u64",width:8}};var yn=163,bn=149,_n=128,qe=86;function wn(e){return(t,r)=>{let n="",s=r+e;for(let i=r;i<s;i++){let o=t.getUint8(i);if(o===0)break;n+=String.fromCharCode(o)}return n}}function vn(e){let t=e.scale;switch(e.kind){case"i8":return t===void 0?(r,n)=>r.getInt8(n):(r,n)=>r.getInt8(n)*t;case"u8":return t===void 0?(r,n)=>r.getUint8(n):(r,n)=>r.getUint8(n)*t;case"i16":return t===void 0?(r,n)=>r.getInt16(n,!0):(r,n)=>r.getInt16(n,!0)*t;case"u16":return t===void 0?(r,n)=>r.getUint16(n,!0):(r,n)=>r.getUint16(n,!0)*t;case"i32":return t===void 0?(r,n)=>r.getInt32(n,!0):(r,n)=>r.getInt32(n,!0)*t;case"u32":return t===void 0?(r,n)=>r.getUint32(n,!0):(r,n)=>r.getUint32(n,!0)*t;case"f32":return(r,n)=>r.getFloat32(n,!0);case"f64":return(r,n)=>r.getFloat64(n,!0);case"i64":return(r,n)=>r.getBigInt64(n,!0);case"u64":return(r,n)=>r.getBigUint64(n,!0);case"str":return wn(e.width)}}function Tn(e,t){let r=[],n=[];for(let i of e){let o=ze[i];if(!o)return{readers:[],widths:[],ok:!1,timeIdx:-1};r.push(vn(o)),n.push(o.width)}let s=t.indexOf("TimeUS");return{readers:r,widths:n,ok:!0,timeIdx:s}}async function We(e,t,r){let n=r??Be(),s=new Map,i={},o=!1,a=null,c=null,l=4194304,u=await pn(e,"r");try{let d=Buffer.allocUnsafe(l),f=new Uint8Array(0),m=0,b=!1;while(!b){let{bytesRead:w}=await u.read(d,0,l,m);m+=w,b=w===0;let h;if(w===0)h=f;else if(f.length===0)h=d.subarray(0,w);else h=new Uint8Array(f.length+w),h.set(f,0),h.set(d.subarray(0,w),f.length);let p=new DataView(h.buffer,h.byteOffset,h.byteLength),g=h.length,_=b,v=performance.now(),T=0;while(T+3<=g){if(h[T]!==yn||h[T+1]!==bn){T+=1;continue}let S=h[T+2],x=T+3;if(S===_n){if(x+qe>g){if(_)o=!0;break}let D=h[x],Ue=h[x+1],Q=be(h,x+2,4),ln=be(h,x+6,16),ye=be(h,x+22,64).split(",").filter((hn)=>hn.length>0),{readers:un,widths:dn,ok:fn,timeIdx:mn}=Tn(ln,ye);s.set(D,{name:Q,length:Ue,columns:ye,ok:fn,payloadLen:Ue-3,readers:un,widths:dn,timeIdx:mn}),t.onFmt(Q,ye),i[Q]=(i[Q]??0)+1,T+=3+qe;continue}let M=s.get(S);if(M===void 0){T+=1;continue}let F=M.payloadLen;if(x+F>g){if(_)o=!0;break}if(i[M.name]=(i[M.name]??0)+1,!M.ok){T+=3+F;continue}let{readers:ge,widths:cn}=M,pe=Array(ge.length),je=x;for(let D=0;D<ge.length;D++)pe[D]=ge[D](p,je),je+=cn[D];if(t.onRow(M.name,pe),M.timeIdx>=0){let D=pe[M.timeIdx];if(typeof D==="bigint")c=D}T+=3+F}if(f=h.slice(T),await Ge(performance.now()-v,n),b)break}}finally{await u.close()}if(o)a=c;return{partial:o,decodedUntil:a,messageCounts:i}}function Xe(e,t,r){let n=e[t];if(!n)e[t]={columns:r,rows:[]};else n.columns=r}async function X(e){let t={},r=await We(e,{onFmt:(n,s)=>Xe(t,n,s),onRow:(n,s)=>{t[n].rows.push(s)}});return{partial:r.partial,decodedUntil:r.decodedUntil,tables:t,messageCounts:r.messageCounts}}async function Ke(e,t,r={}){let n=r.retain??new Set,s=5000,i={},o=new Map,a=await We(e,{onFmt:(c,l)=>{if(Xe(i,c,l),t.table(c,l),!o.has(c))o.set(c,[])},onRow:(c,l)=>{let u=o.get(c);if(u){if(u.push(l),u.length>=5000)t.rows(c,u),u.length=0}if(n.has(c))i[c].rows.push(l)}});for(let[c,l]of o)if(l.length)t.rows(c,l);return{partial:a.partial,decodedUntil:a.decodedUntil,tables:i,messageCounts:a.messageCounts}}function be(e,t,r){let n="",s=t+r;for(let i=t;i<s;i++){let o=e[i];if(o===0)break;n+=String.fromCharCode(o)}return n}import{fileURLToPath as An}from"url";var En="no working Python 3 interpreter found. Install Python >= 3.8 and make sure `python3` "+"(macOS/Linux) or `python` (Windows \u2014 tick \u201CAdd python.exe to PATH\u201D in the installer) runs "+"from a terminal, or set UAV_PYTHON to the interpreter's full path.",_e=null,Ye=!1;function Sn(){let e=process.env.UAV_PYTHON?.trim();if(e)return[[e]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function kn(e){try{return await Bun.spawn([...e,"-c","import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"],{stdout:"ignore",stderr:"ignore",stdin:"ignore",windowsHide:!0}).exited===0}catch{return!1}}async function we(){if(Ye)return _e;for(let e of Sn())if(await kn(e)){_e=e;break}return Ye=!0,_e}async function j(){let e=await we();if(!e)throw Error(En);return e}var Cn=An(new URL("./mavdump.py",import.meta.url)),Rn=new Set(["TimeUS","TimeMS"]);function Je(e){return typeof e==="object"&&e!==null&&"_summary"in e}function Mn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function U(e){let t=await j();if(await Bun.spawn([...t,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited!==0)throw Error(`pymavlink not found \u2014 ${t.join(" ")} -m pip install pymavlink`);let n=Bun.spawn([...t,Cn,e],{stdout:"pipe",stderr:"pipe",windowsHide:!0}),s=new Map,i={},o=!1,a=null,c=null,l=!1;function u(p){let g=s.get(p);if(!g)g={columns:[],colIndex:new Map,rows:[]},s.set(p,g);return g}function d(p){let g=p.t,_=u(g),v=p.f;for(let S of Object.keys(v))if(!_.colIndex.has(S))_.colIndex.set(S,_.columns.length),_.columns.push(S);let T=Array(_.columns.length).fill(null);for(let S of Object.keys(v)){let x=_.colIndex.get(S),M=v[S],F=Rn.has(S)?Mn(M):M;if(T[x]=F,S==="TimeUS"&&typeof F==="bigint")c=F}_.rows.push(T)}let f=new TextDecoder,m="";for await(let p of n.stdout){m+=f.decode(p,{stream:!0});let g;while((g=m.indexOf(`
|
|
3
|
+
`))!==-1){let _=m.slice(0,g);if(m=m.slice(g+1),_.length===0)continue;let v;try{v=JSON.parse(_)}catch{o=!0;continue}if(Je(v)){l=!0;for(let[T,S]of Object.entries(v._summary.counts))i[T]=S;if(v._summary.partial)o=!0}else d(v)}}m+=f.decode();let b=m.trim();if(b.length>0)try{let p=JSON.parse(b);if(Je(p)){l=!0;for(let[g,_]of Object.entries(p._summary.counts))i[g]=_;if(p._summary.partial)o=!0}else d(p)}catch{o=!0}let w=await n.exited;if(w!==0){if(!l){let p=(await new Response(n.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${w})${p?`: ${p}`:""}`)}o=!0}if(!l)o=!0;if(o)a=c;let h={};for(let[p,g]of s)h[p]={columns:g.columns,rows:g.rows};for(let[p,g]of s)if(i[p]===void 0)i[p]=g.rows.length;return{partial:o,decodedUntil:a,tables:h,messageCounts:i}}import{fileURLToPath as $n}from"url";var In=$n(new URL("./ulog.py",import.meta.url)),xn=new Set(["timestamp","timestamp_sample"]);function Fn(e){return typeof e==="object"&&e!==null&&"_summary"in e}function Pn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function Dn(e){let t=()=>Bun.spawn([...e,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited;if(await t()===0)return;if(await Bun.spawn([...e,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited,await t()!==0)throw Error(`pyulog not found \u2014 ${e.join(" ")} -m pip install pyulog`)}async function Z(e){let t=await j();await Dn(t);let r=Bun.spawn([...t,In,e],{stdout:"pipe",stderr:"pipe",windowsHide:!0}),n=new Map,s={},i=!1,o=null,a=null,c=!1;function l(p){let g=n.get(p);if(!g)g={columns:[],colIndex:new Map,rows:[]},n.set(p,g);return g}function u(p){let g=p.t,_=l(g),v=p.f;for(let S of Object.keys(v))if(!_.colIndex.has(S))_.colIndex.set(S,_.columns.length),_.columns.push(S);let T=Array(_.columns.length).fill(null);for(let S of Object.keys(v)){let x=_.colIndex.get(S),M=v[S],F=xn.has(S)?Pn(M):M;if(T[x]=F,S==="timestamp"&&typeof F==="bigint")a=F}_.rows.push(T)}function d(p){if(p.length===0)return;let g;try{g=JSON.parse(p)}catch{i=!0;return}if(Fn(g)){c=!0;for(let[_,v]of Object.entries(g._summary.counts))s[_]=v;if(g._summary.partial)i=!0}else u(g)}let f=new TextDecoder,m="";for await(let p of r.stdout){m+=f.decode(p,{stream:!0});let g;while((g=m.indexOf(`
|
|
4
|
+
`))!==-1)d(m.slice(0,g)),m=m.slice(g+1)}m+=f.decode();let b=m.trim();if(b.length>0)d(b);let w=await r.exited;if(w!==0){if(!c){let p=(await new Response(r.stderr).text()).trim();throw Error(`ulog decode failed (exit ${w})${p?`: ${p}`:""}`)}i=!0}if(!c)i=!0;if(i)o=a;let h={};for(let[p,g]of n)h[p]={columns:g.columns,rows:g.rows};for(let[p,g]of n)if(s[p]===void 0)s[p]=g.rows.length;return{partial:i,decodedUntil:o,tables:h,messageCounts:s}}import{existsSync as Qe,readFileSync as Nn}from"fs";import{mkdtemp as Ln,rm as On}from"fs/promises";import{tmpdir as Hn}from"os";import{basename as ve,join as Te}from"path";function ee(e){if(!e)return[];let t=Te(e,".hydron","uav-format-converters.json");if(!Qe(t))return[];try{let r=JSON.parse(Nn(t,"utf8"));return Array.isArray(r.converters)?r.converters.filter((n)=>n&&n.match&&n.command):[]}catch{return[]}}function te(e,t){for(let r of t)try{if(new RegExp(r.match,"i").test(e))return r}catch{}return null}async function ne(e,t){let r=await Ln(Te(Hn(),"uav-convert-")),n=ve(e).replace(/\.[^.]+$/,""),s=Te(r,n+(t.produces??".bin")),i=t.command.replaceAll("{input}",e).replaceAll("{output}",s),o=()=>On(r,{recursive:!0,force:!0});try{let a=process.platform==="win32"?["cmd.exe","/d","/s","/c",i]:["bash","-lc",i],c=Bun.spawn(a,{stdout:"pipe",stderr:"pipe",windowsHide:!0}),l=await c.exited;if(l!==0){let u=(await new Response(c.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${l}) for ${ve(e)}: ${u}`)}if(!Qe(s))throw Error(`format converter produced no output for ${ve(e)}`);return{out:s,cleanup:o}}catch(a){throw await o(),a}}import{Database as Vn}from"bun:sqlite";import{tmpdir as jn}from"os";import{join as Un}from"path";import{existsSync as Ze,unlinkSync as et}from"fs";var Bn=0;function nt(e){let t=Un(jn(),`uav-${e}-${process.pid}-${Bn++}.sqlite`);try{if(Ze(t))et(t)}catch{}let r=new Vn(t);return r.exec("PRAGMA page_size = 8192"),r.query("PRAGMA journal_mode = MEMORY").get(),r.exec("PRAGMA synchronous = OFF"),r.exec("PRAGMA temp_store = FILE"),r.exec("PRAGMA cache_size = -65536"),{db:r,cleanup(){try{r.close()}catch{}try{if(Ze(t))et(t)}catch{}}}}var Ee=(e)=>`"${e.replace(/"/g,'""')}"`,tt=5000;function Se(e){let t=new Map,r=new Map;return{table(n,s){if(t.has(n)||s.length===0)return;e.run(`CREATE TABLE ${Ee(n)} (${s.map(Ee).join(", ")})`);let i=s.map(()=>"?").join(", ");t.set(n,e.query(`INSERT INTO ${Ee(n)} VALUES (${i})`)),r.set(n,s.length)},rows(n,s){let i=t.get(n),o=r.get(n);if(!i||o===void 0||s.length===0)return;let a=e.transaction((c)=>{for(let l of c){let u=Array(o);for(let d=0;d<o;d++){let f=l[d];u[d]=f===void 0?null:f}i.run(...u)}});for(let c=0;c<s.length;c+=tt)a(s.slice(c,c+tt))}}}function rt(e,t){let r=Se(e);for(let[n,s]of Object.entries(t.tables)){if(s.columns.length===0)continue;if(r.table(n,s.columns),s.rows.length)r.rows(n,s.rows)}}var Gn=new Set(["PARM","MSG","GPS","ERR","MODE"]);async function K(e,t="flight",r){let n=te(e,ee(r?.configDir));if(n){let{out:o,cleanup:a}=await ne(e,n);try{return await K(o,t)}finally{await a()}}let{db:s,cleanup:i}=nt(t);try{let o=e.toLowerCase();if(o.endsWith(".bin"))return{log:await Ke(e,Se(s),{retain:Gn}),db:s,cleanup:i};let a;if(o.endsWith(".ulog"))a=await Z(e);else if(o.endsWith(".tlog")||o.endsWith(".log"))a=await U(e);else try{a=await X(e)}catch{a=await U(e)}return rt(s,a),{log:a,db:s,cleanup:i}}catch(o){throw i(),o}}var re=1e4;async function Wn(e,t,r){let n=st(e,".hydron","observations",t),s;try{s=await zn(n)}catch{throw Error(`No observation store at ${n}. Run uav_analyze first.`)}for(let i of s){let o=st(n,i,`${r}.json`);try{let c=JSON.parse(await qn(o,"utf8"))?.episode?.attrs?.source_path;if(typeof c==="string"&&c)return c;throw Error(`Episode ${r} has no source_path; re-run uav_analyze to record it.`)}catch(a){if(a.code==="ENOENT")continue;throw a}}throw Error(`flight_id ${r} not found in the observation store. Run uav_analyze first.`)}function Xn(e){let t=e.trim();t=t.replace(/^```(?:sql)?\s*/i,"").replace(/\s*```$/,"").trim();for(;;){let s=t;if(t=t.replace(/^--[^\n]*\n?/,"").replace(/^\/\*[\s\S]*?\*\//,"").trimStart(),t===s)break}if(t=t.replace(/;\s*$/,""),t.includes(";"))throw Error("Only a single statement is allowed (no ';').");let r=t.replace(/^\(+\s*/,"");if(!(/^\s*(select|with|values)\b/i.test(r)||/^\s*explain\b/i.test(t)||/^\s*pragma\s+(table_info|table_list|table_xinfo|index_list|index_info|index_xinfo|database_list|collation_list|function_list|pragma_list)\b/i.test(t)))throw Error("uav_query is read-only: use SELECT/WITH/VALUES (comments & ```fences ok), EXPLAIN, or a read PRAGMA (table_info/table_list/index_*). For heavier analysis use Python via bash, not SQL.");if(/\b(insert|update|delete|drop|create|alter|attach|detach|replace|reindex|vacuum)\b/i.test(t))throw Error("Write/DDL keyword detected \u2014 uav_query is read-only.");if(!/\blimit\b/i.test(t))t+=` LIMIT ${re}`;return t}async function it(e){let t=Xn(e.query),r=await Wn(e.projectDir,e.workspace,e.flight_id),{db:n,cleanup:s}=await K(r,e.flight_id);try{n.exec?.("PRAGMA query_only = ON");let o=n.query(t).all(),a=o.length?Object.keys(o[0]):[],l=o.slice(0,re).map((u)=>a.map((d)=>u[d]));return{columns:a,rows:l,truncated:o.length>re}}finally{s()}}function ot(e){if(!e.columns.length)return"(no rows)";let t=e.columns.join(" | "),r=e.rows.slice(0,50).map((s)=>s.map((i)=>typeof i==="bigint"?i.toString():String(i)).join(" | ")).join(`
|
|
5
5
|
`),n=e.rows.length>50?`
|
|
6
6
|
\u2026 ${e.rows.length-50} more rows`:e.truncated?`
|
|
7
7
|
(capped at ${re} rows)`:"";return`${t}
|
|
@@ -20,7 +20,7 @@ ${o}
|
|
|
20
20
|
`),r.push(a)}return r}function He(e,t){let r=t.toLowerCase();return e.findIndex((n)=>n.toLowerCase()===r)}function O(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(typeof e==="string"){let t=Number(e);return Number.isFinite(t)?t:null}return null}function J(e,t){let r,n;if(t.includes("."))[r,n]=t.split(".",2);else n=t,r=Object.keys(e.tables).find((o)=>He(e.tables[o].columns,n)>=0);if(!r)return null;let s=e.tables[r];if(!s)return null;let i=He(s.columns,n);if(i<0)return null;return{table:s,tableName:r,ci:i,ti:He(s.columns,"TimeUS")}}function Qt(e,t){if(e.length<=t)return e;let r=e.length/t,n=[];for(let s=0;s<t;s++){let i=Math.floor(s*r),o=Math.min(e.length,Math.floor((s+1)*r)),a=e[i];for(let c=i;c<o;c++)if(Math.abs(e[c][1])>Math.abs(a[1]))a=e[c];n.push(a)}return n}function fe(e,t,r=1200){let n=J(e,t);if(!n)return null;let s=[],i=null;for(let o of n.table.rows){let a=O(o[n.ci]);if(a===null)continue;let c=n.ti>=0?O(o[n.ti]):s.length,l=c===null?s.length:c;if(i===null)i=l;s.push([n.ti>=0?(l-i)/1e6:l,a])}if(!s.length)return null;return{name:t,points:Qt(s,r)}}function me(e,t,r){let n=J(e,t);if(!n||n.ti<0)return fe(e,t)?xs(fe(e,t),r):null;let s=new Map,i=null;for(let o of n.table.rows){let a=O(o[n.ci]),c=O(o[n.ti]);if(a===null||c===null)continue;if(i===null)i=c;let l=Math.floor((c-i)/1e6/r),u=s.get(l)??{sum:0,n:0};u.sum+=a,u.n++,s.set(l,u)}if(!s.size)return null;return new Map([...s].map(([o,a])=>[o,a.sum/a.n]))}function xs(e,t){let r=new Map;for(let[n,s]of e.points){let i=Math.floor(n/t),o=r.get(i)??{sum:0,n:0};o.sum+=s,o.n++,r.set(i,o)}return new Map([...r].map(([n,s])=>[n,s.sum/s.n]))}var Fs=/^\s*(.+?)\s*([-+*/])\s*(.+?)\s*$/;function Ve(e,t,r){return t==="+"?e+r:t==="-"?e-r:t==="*"?e*r:r===0?NaN:e/r}function Ps(e,t,r=1200){let n=Fs.exec(t);if(!n)return fe(e,t.trim(),r);let[,s,i,o]=n,a=Number(o),c=J(e,s);if(!c)return null;if(Number.isFinite(a)&&!o.includes(".")){let m=fe(e,s,r);if(!m)return null;return{name:t.trim(),points:m.points.map(([b,w])=>[b,Ve(w,i,a)])}}let l=J(e,o);if(!l)return null;if(c.tableName===l.tableName&&c.ti>=0){let m=[],b=null;for(let w of c.table.rows){let h=O(w[c.ci]),p=O(w[l.ci]),g=O(w[c.ti]);if(h===null||p===null||g===null)continue;if(b===null)b=g;m.push([(g-b)/1e6,Ve(h,i,p)])}return m.length?{name:t.trim(),points:Qt(m,r)}:null}let u=me(e,s,0.5),d=me(e,o,0.5);if(!u||!d)return null;let f=[];for(let[m,b]of u){let w=d.get(m);if(w!==void 0)f.push([m*0.5,Ve(b,i,w)])}return f.length?{name:t.trim(),points:f.sort((m,b)=>m[0]-b[0])}:null}function Ds(e,t,r,n=0.5){let s=me(e,t,n),i=me(e,r,n);if(!s||!i)return null;let o=[];for(let[a,c]of s){let l=i.get(a);if(l!==void 0)o.push([c,l])}if(!o.length)return null;return{name:`${r} vs ${t}`,points:o.sort((a,c)=>a[0]-c[0]),kind:"scatter"}}function Ns(e,t){let r=e.length;for(let n=1,s=0;n<r;n++){let i=r>>1;for(;s&i;i>>=1)s^=i;if(s^=i,n<s)[e[n],e[s]]=[e[s],e[n]],[t[n],t[s]]=[t[s],t[n]]}for(let n=2;n<=r;n<<=1){let s=-2*Math.PI/n,i=Math.cos(s),o=Math.sin(s);for(let a=0;a<r;a+=n){let c=1,l=0;for(let u=0;u<n/2;u++){let d=e[a+u],f=t[a+u],m=e[a+u+n/2]*c-t[a+u+n/2]*l,b=e[a+u+n/2]*l+t[a+u+n/2]*c;e[a+u]=d+m,t[a+u]=f+b,e[a+u+n/2]=d-m,t[a+u+n/2]=f-b;let w=c*i-l*o;l=c*o+l*i,c=w}}}}function Ls(e,t,r={}){let n=J(e,t);if(!n||n.ti<0)return null;let s=[],i=[],o=-1/0;for(let h of n.table.rows){let p=O(h[n.ci]),g=O(h[n.ti]);if(p===null||g===null||g<=o)continue;s.push(p),i.push(g),o=g}if(s.length<16)return null;let a=[];for(let h=1;h<i.length;h++)a.push(i[h]-i[h-1]);a.sort((h,p)=>h-p);let c=a[a.length>>1]/1e6;if(!(c>0))return null;let l=1/c,u=s.reduce((h,p)=>h+p,0)/s.length,d=1;while(d<s.length)d<<=1;let f=Array(d).fill(0),m=Array(d).fill(0);for(let h=0;h<s.length;h++)f[h]=s[h]-u;Ns(f,m);let b=r.fMax??Math.min(l/2,250),w=[];for(let h=1;h<d/2;h++){let p=h*l/d;if(p>b)break;w.push([p,Math.hypot(f[h],m[h])/s.length])}return w.length?{name:`FFT ${t}`,points:w}:null}var Yt=["#2563eb","#dc2626","#16a34a","#d97706","#9333ea","#0891b2"];function Jt(e,t={}){let r=t.width??900,n=t.height??380,s={l:60,r:150,t:34,b:40},i=r-s.l-s.r,o=n-s.t-s.b,a=(_)=>_.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),c=e.flatMap((_)=>_.points);if(!c.length)return`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${n}"><text x="20" y="30">no data</text></svg>`;let l=c.map((_)=>_[0]),u=c.map((_)=>_[1]),d=Math.min(...l),f=Math.max(...l),m=Math.min(...u),b=Math.max(...u);if(f===d)f=d+1;if(b===m)b=m+1,m-=1;let w=(b-m)*0.06;m-=w,b+=w;let h=(_)=>s.l+(_-d)/(f-d)*i,p=(_)=>s.t+(1-(_-m)/(b-m))*o,g=[];if(g.push(`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${n}" font-family="ui-sans-serif,system-ui,sans-serif" font-size="12">`),g.push(`<rect width="${r}" height="${n}" fill="#ffffff"/>`),t.title)g.push(`<text x="${s.l}" y="20" font-weight="600">${a(t.title)}</text>`);g.push(`<rect x="${s.l}" y="${s.t}" width="${i}" height="${o}" fill="none" stroke="#e5e7eb"/>`);for(let _=0;_<=5;_++){let v=m+_/5*(b-m),T=p(v);g.push(`<line x1="${s.l}" y1="${T}" x2="${s.l+i}" y2="${T}" stroke="#f1f5f9"/>`),g.push(`<text x="${s.l-6}" y="${T+4}" text-anchor="end" fill="#64748b">${v.toFixed(2)}</text>`)}for(let _ of[0,0.5,1]){let v=d+_*(f-d);g.push(`<text x="${h(v)}" y="${s.t+o+22}" text-anchor="middle" fill="#64748b">${v.toFixed(f-d<10?2:0)}</text>`)}return g.push(`<text x="${s.l+i/2}" y="${n-6}" text-anchor="middle" fill="#475569">${a(t.xLabel??"s")}</text>`),e.forEach((_,v)=>{let T=Yt[v%Yt.length];if(_.kind==="scatter")for(let S of _.points)g.push(`<circle cx="${h(S[0]).toFixed(1)}" cy="${p(S[1]).toFixed(1)}" r="1.8" fill="${T}" fill-opacity="0.6"/>`);else{let S=_.points.map((x,M)=>`${M===0?"M":"L"}${h(x[0]).toFixed(1)},${p(x[1]).toFixed(1)}`).join(" ");g.push(`<path d="${S}" fill="none" stroke="${T}" stroke-width="1.2"/>`)}g.push(`<rect x="${s.l+i+14}" y="${s.t+4+v*18}" width="10" height="10" fill="${T}"/>`),g.push(`<text x="${s.l+i+28}" y="${s.t+13+v*18}" fill="#334155">${a(_.name)}</text>`)}),g.push("</svg>"),g.join("")}function Zt(e,t){let r=t.mode??"timeseries",n=[],s=[],i="s";if(r==="xy"){if(!t.x||!t.y)return{svg:Jt([]),plotted:[],missing:["x and y required for xy mode"],xLabel:""};let a=Ds(e,t.x,t.y);if(a)n.push(a);else s.push(`${t.y} vs ${t.x}`);i=t.x}else if(r==="fft"){for(let a of t.signals??[]){let c=Ls(e,a);if(c)n.push(c);else s.push(a)}i="Hz"}else{for(let a of t.signals??[]){let c=Ps(e,a,t.points??1200);if(c&&c.points.length)n.push(c);else s.push(a)}i="s"}let o=t.title??(n.map((a)=>a.name).join(", ")||r);return{svg:Jt(n,{title:o,xLabel:i}),plotted:n.map((a)=>a.name),missing:s,xLabel:i}}var Os=[{match:/\bVIBE\b|\bVibe[XYZ]\b/i,note:"VIBE = whole-airframe vibration at the IMU (per IMU instance) \u2014 NOT per-motor. To blame a motor, correlate the FFT peak Hz with that motor's RPM."},{match:/CTUN\.ThH\b|\bThH\b/i,note:"CTUN.ThH = slow hover-throttle estimate (~constant), NOT instantaneous throttle \u2014 use RCOU (motor PWM) or CTUN.ThO."},{match:/\bRCOU\b|RCOU\.C\d/i,note:"RCOU.Cn = per-motor/servo PWM output (\xB5s)."},{match:/XKF3|NKF3|\bI[VP][NEDT]\b/i,note:"XKF3/NKF3 innovations: velocity (IVN/IVE/IVD) reflect vibration stress; position (IPN/IPE/IPD) reflect GPS."}];function en(e){let t=e.join(" "),r=[];for(let{match:n,note:s}of Os)if(n.test(t)&&!r.includes(s))r.push(s);return r}import{readdir as Hs,writeFile as Vs}from"fs/promises";import{join as js}from"path";async function tn(e,t,r={}){let n=(await Hs(e).catch(()=>[])).filter((m)=>m.endsWith(".csv")).map((m)=>m.slice(0,-4)).sort(),s=["import os, sys, json","import pandas as pd, numpy as np",`CSV_DIR = ${JSON.stringify(e)}`,"_cache = {}","def load(name):"," if name not in _cache:"," _cache[name] = pd.read_csv(os.path.join(CSV_DIR, name + '.csv'))"," return _cache[name]",`# Message tables available via load('NAME'): ${n.join(", ")}`,"# TimeUS is microseconds since boot; seconds = (TimeUS - TimeUS.iloc[0]) / 1e6",""].join(`
|
|
21
21
|
`),i=js(e,"_uav_snippet.py");await Vs(i,s+`
|
|
22
22
|
`+t+`
|
|
23
|
-
`);let o=await j(),a=Bun.spawn([...o,i],{stdout:"pipe",stderr:"pipe"}),c=setTimeout(()=>a.kill(9),r.timeoutMs??30000),[l,u,d]=await Promise.all([new Response(a.stdout).text(),new Response(a.stderr).text(),a.exited]);return clearTimeout(c),{stdout:(l+(u.trim()?`
|
|
23
|
+
`);let o=await j(),a=Bun.spawn([...o,i],{stdout:"pipe",stderr:"pipe",windowsHide:!0}),c=setTimeout(()=>a.kill(9),r.timeoutMs??30000),[l,u,d]=await Promise.all([new Response(a.stdout).text(),new Response(a.stderr).text(),a.exited]);return clearTimeout(c),{stdout:(l+(u.trim()?`
|
|
24
24
|
--- stderr ---
|
|
25
25
|
${u.trim()}`:"")).trim().slice(0,12000),ok:d===0,tables:n}}import{existsSync as an}from"fs";async function W(e,t){let r=te(e,ee(t?.configDir));if(r){let{out:s,cleanup:i}=await ne(e,r);try{return await W(s)}finally{await i()}}let n=e.toLowerCase();if(n.endsWith(".bin"))return X(e);if(n.endsWith(".ulog"))return Z(e);if(n.endsWith(".tlog")||n.endsWith(".log"))return U(e);return X(e).catch(()=>U(e))}function qs(e){let t=[];if(e.partial_decode)t.push(`\u26A0\uFE0F PARTIAL DECODE \u2014 log truncated at TimeUS=${e.decoded_until}. Post-cut checks were SKIPPED.`);t.push(`Flight ${e.flight_id} \xB7 ${e.metadata.airframe}`+(e.metadata.firmware?` \xB7 ${e.metadata.firmware}`:"")+(e.metadata.duration_s?` \xB7 ${Math.round(e.metadata.duration_s/60)}min`:"")),t.push(`Checks: ${e.summary.total} run \xB7 ${e.summary.passed} clean \xB7 ${e.summary.anomalies} anomalies (${e.summary.critical} critical) \xB7 ruleset ${e.ruleset_version}`);let r=e.checks.filter((s)=>s.verdict==="FAIL").sort((s,i)=>nn(i.severity)-nn(s.severity));for(let s of r){let i=s.source?` [${s.source.kind}${s.source.ref?`: ${s.source.ref}`:""}]`:"";t.push(` ${s.severity.padEnd(8)} ${s.check}: value=${s.value??"\u2014"} vs threshold=${s.threshold_used??"\u2014"}${i}`)}let n=e.checks.filter((s)=>s.verdict==="SKIP").map((s)=>s.check);if(n.length)t.push(` (skipped \u2014 data absent: ${n.join(", ")})`);if(e.comparison){t.push(`
|
|
26
26
|
vs prior flight ${e.comparison.prior_flight_id}:`);for(let s of e.comparison.param_changes)t.push(` param ${s.name}: ${s.old} \u2192 ${s.new}`);for(let s of e.comparison.finding_changes)t.push(` finding ${s.check}: ${s.old} \u2192 ${s.new}`);if(!e.comparison.param_changes.length&&!e.comparison.finding_changes.length)t.push(" (no changes)")}else t.push(`
|
|
@@ -28,7 +28,7 @@ vs prior flight ${e.comparison.prior_flight_id}:`);for(let s of e.comparison.par
|
|
|
28
28
|
`)}var nn=(e)=>e==="CRITICAL"?2:e==="HIGH"?1:0;function Ws(e){if(!e.length)return"(no findings stored for this flight yet)";let t=e.filter((i)=>i.origin!=="agent"),r=e.filter((i)=>i.origin==="agent"),n=(i)=>` ${i.origin==="agent"?`[agent ${i.id}]`:"[deterministic]"} ${i.severity}/${i.verdict} ${i.check}${i.detail?` \u2014 ${i.detail}`:""}`,s=[`${e.length} finding(s) stored:`];return s.push(`Deterministic (${t.length}):`,...t.map(n)),s.push(`Agent-authored (${r.length}):`,...r.length?r.map(n):[" (none)"]),s.push("","Before adding, judge whether your finding is ALREADY represented above (same root cause, even if phrased differently). Add only if genuinely new; pass supersedes_id to replace a stale one."),s.join(`
|
|
29
29
|
`)}async function Xs(e,t,r){let n=H(e,".hydron","observations",t),s=await sn(n).catch(()=>{throw Error(`No observation store at ${n}. Run uav_analyze first.`)});for(let i of s){let o=H(n,i,`${r}.json`);try{let a=JSON.parse(await on(o,"utf8"));if(Array.isArray(a?.params))return a.params}catch(a){if(a.code==="ENOENT")continue;throw a}}throw Error(`flight_id ${r} not found in the observation store. Run uav_analyze first.`)}async function he(e,t,r){let n=H(e,".hydron","observations",t),s=await sn(n).catch(()=>{throw Error(`No observation store at ${n}. Run uav_analyze first.`)});for(let i of s)try{let a=JSON.parse(await on(H(n,i,`${r}.json`),"utf8"))?.episode?.attrs?.source_path;if(typeof a==="string"&&a)return a}catch(o){if(o.code==="ENOENT")continue;throw o}throw Error(`flight_id ${r} not found (or no source_path). Run uav_analyze first.`)}function Ks(e){if(e.dominant_peak_hz==null)return`No notch recommendation: ${e.rationale}`;let t=[`Dominant vibration peak: ${e.dominant_peak_hz.toFixed(1)} Hz`,e.rationale,"","Recommended harmonic-notch params:"];for(let r of e.params){let n=r.range?` (range ${r.range[0]}\u2013${r.range[1]})`:"",s=r.source?` [${r.source.kind}${r.source.ref?`: ${r.source.ref}`:""}]`:"";t.push(` ${r.name} = ${r.value}${n}${s}`)}return t.push("","Review before applying. Push via the gated MAVLink param link, then tag the retest."),t.join(`
|
|
30
30
|
`)}var Ys=["# UAV domain pack active","","This project uses the Hydron UAV pack for ArduPilot/PX4 flight-log intelligence. Handle UAV","work (flight logs, parameters, tuning, telemetry) in whatever mode you are already in \u2014 do","NOT switch to a dedicated agent. The `uav_*` tools are available now: `uav_analyze` (decode +","run the system checks on a .bin/.log/.ulog/.tlog), `uav_query` (read-only SQL over a decoded","flight), `uav_python` (pandas/numpy over its tables \u2014 the tool for any non-trivial","computation), `uav_plot` (charts), `uav_param_audit`, `uav_tune`, `uav_tag`, `uav_finding`,","`uav_export`.","","For the domain rules \u2014 grounding discipline (the guardrails judge, you narrate; cite every","bound's source; never invent a threshold), signal semantics, per-check interpretation, the","tuning playbook, and when to fan work out \u2014 **load the `uav` skill**. Load it as soon as you","start UAV work, not only when narrating results.","","Specialist loops (spawn only for a genuine multi-step drill-down): `uav-investigate`","(open-ended 'why' on one flight), `uav-compare` (cross-flight regression), `uav-verify`","(adversarially pressure-test a proposed anomaly)."].join(`
|
|
31
|
-
`),rn=Gs(zs(import.meta.url)),Js=[H(rn,"..","bridge","uav_mavlink_bridge.py"),H(rn,"..","..","bridge","uav_mavlink_bridge.py")];function Qs(){return Js.find((e)=>an(e))}async function Zs(e){try{return await Bun.spawn([...e,"-c","import mcp, pymavlink"],{stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}var ei=async(e)=>{let t=e.directory,r=e.project?.id!=null?String(e.project.id):"local";return{config:async(n)=>{let s=Qs();if(!s)return;let i=await we();if(!i)return;n.mcp={...n.mcp,mavlink:{type:"local",command:[...i,s,"--no-read-only","--allow-param-write"],environment:{MAVLINK_DIALECT:"ardupilotmega"},enabled:await Zs(i),timeout:1e4}}},"experimental.chat.system.transform":async(n,s)=>{s.system.push(Ys)},tool:{uav_analyze:E({description:"Analyze one ArduPilot/PX4 flight log (.bin): decode, run the UAV system checks, persist the observation locally, and (if a prior flight for the same airframe exists) compute the param/finding diff. Returns a ranked anomaly report. Verdicts come from deterministic guardrails, not the model.",args:{path:E.schema.string().describe("Absolute path to the .bin DataFlash log")},async execute(n){let{report:s}=await Bt(n.path,{projectDir:t,workspace:r});return qs(s)}}),uav_query:E({description:"Ask an ad-hoc SQL question over a single decoded flight's message tables (one table per message type, e.g. VIBE, ATT, BAT, ERR, CTUN, RCOU). Read-only: SELECT/WITH only, single statement, capped at 10k rows. Use the table/column names from the ArduPilot log. Findings produced this way are exploratory (tier:user), not part of the regression record.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),query:E.schema.string().describe("read-only SQL (SELECT/WITH) over the flight's message tables")},async execute(n){try{let s=await Gt({projectDir:t,workspace:r,flight_id:n.flight_id,query:n.query});return ot(s)}catch(s){return`uav_query error: ${s instanceof Error?s.message:String(s)}`}}}),uav_compare:E({description:"Compare 2+ ALREADY-ANALYZED flights at once: finding-severity trend (only checks that "+"differ), key-metric trend (vibe_peak, hover_thr, \u2026), and parameter drift across the runs. "+"Analyze each flight first with uav_analyze. Memory-light \u2014 compares the stored per-flight "+"summaries, NOT the raw logs, so four 1 GB flights compare cheaply. Returns a markdown report.",args:{flight_ids:E.schema.array(E.schema.string()).describe("2+ flight_ids from prior uav_analyze runs, in the order to display")},async execute(n){try{let{markdown:s}=await qt({projectDir:t,workspace:r,flight_ids:n.flight_ids});return s}catch(s){return`uav_compare error: ${s instanceof Error?s.message:String(s)}`}}}),uav_param_audit:E({description:"Audit a flight's ArduPilot parameters for safety-critical settings (arming checks, battery/radio failsafes), out-of-range tuning values, and consistency (cell-count vs failsafe voltages, frame/notch). Deterministic; bounds come from param-rules.yaml + built-in defaults. (uav_analyze already includes this; use this for a standalone param re-audit of a stored flight.)",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze")},async execute(n){try{let s=await Xs(t,r,n.flight_id);return bt(ie(s,{configDir:t}))}catch(s){return`uav_param_audit error: ${s instanceof Error?s.message:String(s)}`}}}),uav_tune:E({description:"Compute an FFT over a flight's gyro/vibration data, find the dominant vibration peak, and recommend ArduPilot harmonic-notch params (INS_HNTCH_ENABLE/FREQ/BW/REF/HMNCS) with their verified ranges. "+"Recommendation only \u2014 review before applying; pushing params is a separate gated step.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze")},async execute(n){try{let s=await W(await he(t,r,n.flight_id),{configDir:t});return Ks(Kt(s))}catch(s){return`uav_tune error: ${s instanceof Error?s.message:String(s)}`}}}),uav_tag:E({description:"Tag a stored flight with test-profile / campaign labels (e.g. 'notch-v2', 'windy', 'post-prop-balance') for the param-history / run-tracking record. Returns the flight's full tag set.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),tags:E.schema.array(E.schema.string()).describe("one or more tags to add")},async execute(n){try{let s=await Ft({projectDir:t,workspace:r,flight_id:n.flight_id,tags:n.tags});return`tagged ${n.flight_id}: [${s.join(", ")}]`}catch(s){return`uav_tag error: ${s instanceof Error?s.message:String(s)}`}}}),uav_finding:E({description:`Store or list a flight's findings. Findings from uav_analyze are deterministic; THIS tool records the conclusions YOU reach during an investigation so they attach to the flight.
|
|
31
|
+
`),rn=Gs(zs(import.meta.url)),Js=[H(rn,"..","bridge","uav_mavlink_bridge.py"),H(rn,"..","..","bridge","uav_mavlink_bridge.py")];function Qs(){return Js.find((e)=>an(e))}async function Zs(e){try{return await Bun.spawn([...e,"-c","import mcp, pymavlink"],{stdout:"ignore",stderr:"ignore",stdin:"ignore",windowsHide:!0}).exited===0}catch{return!1}}var ei=async(e)=>{let t=e.directory,r=e.project?.id!=null?String(e.project.id):"local";return{config:async(n)=>{let s=Qs();if(!s)return;let i=await we();if(!i)return;n.mcp={...n.mcp,mavlink:{type:"local",command:[...i,s,"--no-read-only","--allow-param-write"],environment:{MAVLINK_DIALECT:"ardupilotmega"},enabled:await Zs(i),timeout:1e4}}},"experimental.chat.system.transform":async(n,s)=>{s.system.push(Ys)},tool:{uav_analyze:E({description:"Analyze one ArduPilot/PX4 flight log (.bin): decode, run the UAV system checks, persist the observation locally, and (if a prior flight for the same airframe exists) compute the param/finding diff. Returns a ranked anomaly report. Verdicts come from deterministic guardrails, not the model.",args:{path:E.schema.string().describe("Absolute path to the .bin DataFlash log")},async execute(n){let{report:s}=await Bt(n.path,{projectDir:t,workspace:r});return qs(s)}}),uav_query:E({description:"Ask an ad-hoc SQL question over a single decoded flight's message tables (one table per message type, e.g. VIBE, ATT, BAT, ERR, CTUN, RCOU). Read-only: SELECT/WITH only, single statement, capped at 10k rows. Use the table/column names from the ArduPilot log. Findings produced this way are exploratory (tier:user), not part of the regression record.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),query:E.schema.string().describe("read-only SQL (SELECT/WITH) over the flight's message tables")},async execute(n){try{let s=await Gt({projectDir:t,workspace:r,flight_id:n.flight_id,query:n.query});return ot(s)}catch(s){return`uav_query error: ${s instanceof Error?s.message:String(s)}`}}}),uav_compare:E({description:"Compare 2+ ALREADY-ANALYZED flights at once: finding-severity trend (only checks that "+"differ), key-metric trend (vibe_peak, hover_thr, \u2026), and parameter drift across the runs. "+"Analyze each flight first with uav_analyze. Memory-light \u2014 compares the stored per-flight "+"summaries, NOT the raw logs, so four 1 GB flights compare cheaply. Returns a markdown report.",args:{flight_ids:E.schema.array(E.schema.string()).describe("2+ flight_ids from prior uav_analyze runs, in the order to display")},async execute(n){try{let{markdown:s}=await qt({projectDir:t,workspace:r,flight_ids:n.flight_ids});return s}catch(s){return`uav_compare error: ${s instanceof Error?s.message:String(s)}`}}}),uav_param_audit:E({description:"Audit a flight's ArduPilot parameters for safety-critical settings (arming checks, battery/radio failsafes), out-of-range tuning values, and consistency (cell-count vs failsafe voltages, frame/notch). Deterministic; bounds come from param-rules.yaml + built-in defaults. (uav_analyze already includes this; use this for a standalone param re-audit of a stored flight.)",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze")},async execute(n){try{let s=await Xs(t,r,n.flight_id);return bt(ie(s,{configDir:t}))}catch(s){return`uav_param_audit error: ${s instanceof Error?s.message:String(s)}`}}}),uav_tune:E({description:"Compute an FFT over a flight's gyro/vibration data, find the dominant vibration peak, and recommend ArduPilot harmonic-notch params (INS_HNTCH_ENABLE/FREQ/BW/REF/HMNCS) with their verified ranges. "+"Recommendation only \u2014 review before applying; pushing params is a separate gated step.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze")},async execute(n){try{let s=await W(await he(t,r,n.flight_id),{configDir:t});return Ks(Kt(s))}catch(s){return`uav_tune error: ${s instanceof Error?s.message:String(s)}`}}}),uav_tag:E({description:"Tag a stored flight with test-profile / campaign labels (e.g. 'notch-v2', 'windy', 'post-prop-balance') for the param-history / run-tracking record. Returns the flight's full tag set.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),tags:E.schema.array(E.schema.string()).describe("one or more tags to add")},async execute(n){try{let s=await Ft({projectDir:t,workspace:r,flight_id:n.flight_id,tags:n.tags});return`tagged ${n.flight_id}: [${s.join(", ")}]`}catch(s){return`uav_tag error: ${s instanceof Error?s.message:String(s)}`}}}),uav_finding:E({description:`Store or list a flight's findings. Findings from uav_analyze are deterministic; THIS tool records the conclusions YOU reach during an investigation so they attach to the flight.
|
|
32
32
|
`+`\u2022 op:"list" \u2014 show every stored finding (deterministic + agent). ALWAYS call this first.
|
|
33
33
|
`+'\u2022 op:"add" \u2014 append a NEW agent finding. Only add after listing and judging it is not already '+"represented (same root cause, even if worded differently). To replace one you now consider stale, "+"pass supersedes_id. A finding must cite the ABSOLUTE bound it breached (in detail) \u2014 not 'N\xD7 the "+"other instances'. The store refuses an exact-id rewrite but does NOT dedup semantically; that is your call.",args:{op:E.schema.enum(["list","add"]).describe("list existing findings, or add a new one"),flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),title:E.schema.string().optional().describe("add: short label, e.g. 'IMU2 accel-Y divergence'"),severity:E.schema.enum(["OK","HIGH","CRITICAL"]).optional().describe("add: magnitude (default HIGH)"),detail:E.schema.string().optional().describe("add: the grounded evidence + the ABSOLUTE bound it breached and that bound's source"),value:E.schema.number().optional().describe("add: measured metric, if any"),threshold_used:E.schema.number().optional().describe("add: the absolute bound it was judged against"),supersedes_id:E.schema.string().optional().describe("add: id of an existing finding this replaces")},async execute(n){try{if(n.op==="list")return Ws(await Pt({projectDir:t,workspace:r,flight_id:n.flight_id}));if(!n.title)return"uav_finding error: title is required to add a finding";let s=n.severity??"HIGH",i={check:n.title,severity:s,verdict:s==="OK"?"PASS":"FAIL",tier:"user",origin:"agent",value:n.value??null,threshold_used:n.threshold_used??null,ruleset_version:"",detail:n.detail,id:`a-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,created_at:new Date().toISOString()},o=await Nt({projectDir:t,workspace:r,flight_id:n.flight_id,finding:i,supersedesId:n.supersedes_id});return o.added?`stored agent finding ${o.id} on ${n.flight_id} (${o.total} findings total)`+(n.supersedes_id?` \u2014 superseded ${n.supersedes_id}`:""):`not stored (${o.reason}); ${o.total} findings already on ${n.flight_id}`}catch(s){return`uav_finding error: ${s instanceof Error?s.message:String(s)}`}}}),uav_python:E({description:"Run a Python snippet (pandas + numpy) over a flight's decoded data \u2014 THE tool for any non-trivial "+"analysis: binning, correlation, scoring/ranking windows, regression, FFT, custom stats. The message "+"tables are available as `load('VIBE')`, `load('ATT')`, `load('BAT')`, \u2026 (each a DataFrame; TimeUS is \xB5s "+"since boot). `print()` your results. Use this INSTEAD of multiple uav_query calls or doing arithmetic "+"in your head \u2014 the numbers must come from code you actually run.",args:{flight_id:E.schema.string().describe("flight_id from a prior uav_analyze"),code:E.schema.string().describe("Python; use load('TABLE') for DataFrames, print() results")},async execute(n){try{let s=H(t,".hydron","pycache",n.flight_id);if(!an(s)){let c=await W(await he(t,r,n.flight_id),{configDir:t});await Oe(c,s)}let{stdout:i,ok:o,tables:a}=await tn(s,n.code);return o?i||"(snippet ran, no output \u2014 did you print()?)":`python exited non-zero:
|
|
34
34
|
${i}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var M=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};function Ee(){let e=process.env.UAV_DECODE_MAX_CPU;if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0&&t<1?t:void 0}async function Ae(e,t){if(!t||e<=0)return;let n=Math.min(e*(1/t-1),250);if(n>=1)await Vt(n)}var Vt=(e)=>new Promise((t)=>setTimeout(t,e));var ke;var Te=M(()=>{ke={a:{kind:"str",width:64},b:{kind:"i8",width:1},B:{kind:"u8",width:1},h:{kind:"i16",width:2},H:{kind:"u16",width:2},i:{kind:"i32",width:4},I:{kind:"u32",width:4},f:{kind:"f32",width:4},d:{kind:"f64",width:8},n:{kind:"str",width:4},N:{kind:"str",width:16},Z:{kind:"str",width:64},c:{kind:"i16",width:2,scale:0.01},C:{kind:"u16",width:2,scale:0.01},e:{kind:"i32",width:4,scale:0.01},E:{kind:"u32",width:4,scale:0.01},L:{kind:"i32",width:4,scale:0.0000001},M:{kind:"u8",width:1},q:{kind:"i64",width:8},Q:{kind:"u64",width:8}}});import{open as Bt}from"fs/promises";function Xt(e){return(t,n)=>{let r="",s=n+e;for(let i=n;i<s;i++){let o=t.getUint8(i);if(o===0)break;r+=String.fromCharCode(o)}return r}}function qt(e){let t=e.scale;switch(e.kind){case"i8":return t===void 0?(n,r)=>n.getInt8(r):(n,r)=>n.getInt8(r)*t;case"u8":return t===void 0?(n,r)=>n.getUint8(r):(n,r)=>n.getUint8(r)*t;case"i16":return t===void 0?(n,r)=>n.getInt16(r,!0):(n,r)=>n.getInt16(r,!0)*t;case"u16":return t===void 0?(n,r)=>n.getUint16(r,!0):(n,r)=>n.getUint16(r,!0)*t;case"i32":return t===void 0?(n,r)=>n.getInt32(r,!0):(n,r)=>n.getInt32(r,!0)*t;case"u32":return t===void 0?(n,r)=>n.getUint32(r,!0):(n,r)=>n.getUint32(r,!0)*t;case"f32":return(n,r)=>n.getFloat32(r,!0);case"f64":return(n,r)=>n.getFloat64(r,!0);case"i64":return(n,r)=>n.getBigInt64(r,!0);case"u64":return(n,r)=>n.getBigUint64(r,!0);case"str":return Xt(e.width)}}function Wt(e,t){let n=[],r=[];for(let i of e){let o=ke[i];if(!o)return{readers:[],widths:[],ok:!1,timeIdx:-1};n.push(qt(o)),r.push(o.width)}let s=t.indexOf("TimeUS");return{readers:n,widths:r,ok:!0,timeIdx:s}}async function Ce(e,t,n){let r=n??Ee(),s=new Map,i={},o=!1,a=null,c=null,l=4194304,u=await Bt(e,"r");try{let f=Buffer.allocUnsafe(l),p=new Uint8Array(0),g=0,k=!1;while(!k){let{bytesRead:S}=await u.read(f,0,l,g);g+=S,k=S===0;let y;if(S===0)y=p;else if(p.length===0)y=f.subarray(0,S);else y=new Uint8Array(p.length+S),y.set(p,0),y.set(f.subarray(0,S),p.length);let h=new DataView(y.buffer,y.byteOffset,y.byteLength),m=y.length,v=k,b=performance.now(),w=0;while(w+3<=m){if(y[w]!==jt||y[w+1]!==Ut){w+=1;continue}let E=y[w+2],F=w+3;if(E===Gt){if(F+Se>m){if(v)o=!0;break}let O=y[F],ve=y[F+1],U=Z(y,F+2,4),$t=Z(y,F+6,16),Q=Z(y,F+22,64).split(",").filter((Ht)=>Ht.length>0),{readers:Ot,widths:xt,ok:Lt,timeIdx:Nt}=Wt($t,Q);s.set(O,{name:U,length:ve,columns:Q,ok:Lt,payloadLen:ve-3,readers:Ot,widths:xt,timeIdx:Nt}),t.onFmt(U,Q),i[U]=(i[U]??0)+1,w+=3+Se;continue}let R=s.get(E);if(R===void 0){w+=1;continue}let P=R.payloadLen;if(F+P>m){if(v)o=!0;break}if(i[R.name]=(i[R.name]??0)+1,!R.ok){w+=3+P;continue}let{readers:z,widths:Dt}=R,Y=Array(z.length),we=F;for(let O=0;O<z.length;O++)Y[O]=z[O](h,we),we+=Dt[O];if(t.onRow(R.name,Y),R.timeIdx>=0){let O=Y[R.timeIdx];if(typeof O==="bigint")c=O}w+=3+P}if(p=y.slice(w),await Ae(performance.now()-b,r),k)break}}finally{await u.close()}if(o)a=c;return{partial:o,decodedUntil:a,messageCounts:i}}function Re(e,t,n){let r=e[t];if(!r)e[t]={columns:n,rows:[]};else r.columns=n}async function Me(e){let t={},n=await Ce(e,{onFmt:(r,s)=>Re(t,r,s),onRow:(r,s)=>{t[r].rows.push(s)}});return{partial:n.partial,decodedUntil:n.decodedUntil,tables:t,messageCounts:n.messageCounts}}async function Ie(e,t,n={}){let r=n.retain??new Set,s=5000,i={},o=new Map,a=await Ce(e,{onFmt:(c,l)=>{if(Re(i,c,l),t.table(c,l),!o.has(c))o.set(c,[])},onRow:(c,l)=>{let u=o.get(c);if(u){if(u.push(l),u.length>=5000)t.rows(c,u),u.length=0}if(r.has(c))i[c].rows.push(l)}});for(let[c,l]of o)if(l.length)t.rows(c,l);return{partial:a.partial,decodedUntil:a.decodedUntil,tables:i,messageCounts:a.messageCounts}}function Z(e,t,n){let r="",s=t+n;for(let i=t;i<s;i++){let o=e[i];if(o===0)break;r+=String.fromCharCode(o)}return r}var jt=163,Ut=149,Gt=128,Se=86;var Fe=M(()=>{Te()});function Kt(){let e=process.env.UAV_PYTHON?.trim();if(e)return[[e]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function zt(e){try{return await Bun.spawn([...e,"-c","import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"],{stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}async function Yt(){if(Pe)return ee;for(let e of Kt())if(await zt(e)){ee=e;break}return Pe=!0,ee}async function G(){let e=await Yt();if(!e)throw Error(Jt);return e}var Jt,ee=null,Pe=!1;var te=M(()=>{Jt="no working Python 3 interpreter found. Install Python >= 3.8 and make sure `python3` "+"(macOS/Linux) or `python` (Windows \u2014 tick \u201CAdd python.exe to PATH\u201D in the installer) runs "+"from a terminal, or set UAV_PYTHON to the interpreter's full path."});import{fileURLToPath as Qt}from"url";function De(e){return typeof e==="object"&&e!==null&&"_summary"in e}function tn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function ne(e){let t=await G();if(await Bun.spawn([...t,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore"}).exited!==0)throw Error(`pymavlink not found \u2014 ${t.join(" ")} -m pip install pymavlink`);let r=Bun.spawn([...t,Zt,e],{stdout:"pipe",stderr:"pipe"}),s=new Map,i={},o=!1,a=null,c=null,l=!1;function u(h){let m=s.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},s.set(h,m);return m}function f(h){let m=h.t,v=u(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=en.has(E)?tn(R):R;if(w[F]=P,E==="TimeUS"&&typeof P==="bigint")c=P}v.rows.push(w)}let p=new TextDecoder,g="";for await(let h of r.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
3
|
-
`))!==-1){let v=g.slice(0,m);if(g=g.slice(m+1),v.length===0)continue;let b;try{b=JSON.parse(v)}catch{o=!0;continue}if(De(b)){l=!0;for(let[w,E]of Object.entries(b._summary.counts))i[w]=E;if(b._summary.partial)o=!0}else f(b)}}g+=p.decode();let k=g.trim();if(k.length>0)try{let h=JSON.parse(k);if(De(h)){l=!0;for(let[m,v]of Object.entries(h._summary.counts))i[m]=v;if(h._summary.partial)o=!0}else f(h)}catch{o=!0}let S=await r.exited;if(S!==0){if(!l){let h=(await new Response(r.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${S})${h?`: ${h}`:""}`)}o=!0}if(!l)o=!0;if(o)a=c;let y={};for(let[h,m]of s)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of s)if(i[h]===void 0)i[h]=m.rows.length;return{partial:o,decodedUntil:a,tables:y,messageCounts:i}}var Zt,en;var $e=M(()=>{te();Zt=Qt(new URL("./mavdump.py",import.meta.url)),en=new Set(["TimeUS","TimeMS"])});import{fileURLToPath as nn}from"url";function on(e){return typeof e==="object"&&e!==null&&"_summary"in e}function an(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function cn(e){let t=()=>Bun.spawn([...e,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore"}).exited;if(await t()===0)return;if(await Bun.spawn([...e,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore"}).exited,await t()!==0)throw Error(`pyulog not found \u2014 ${e.join(" ")} -m pip install pyulog`)}async function Oe(e){let t=await G();await cn(t);let n=Bun.spawn([...t,rn,e],{stdout:"pipe",stderr:"pipe"}),r=new Map,s={},i=!1,o=null,a=null,c=!1;function l(h){let m=r.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},r.set(h,m);return m}function u(h){let m=h.t,v=l(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=sn.has(E)?an(R):R;if(w[F]=P,E==="timestamp"&&typeof P==="bigint")a=P}v.rows.push(w)}function f(h){if(h.length===0)return;let m;try{m=JSON.parse(h)}catch{i=!0;return}if(on(m)){c=!0;for(let[v,b]of Object.entries(m._summary.counts))s[v]=b;if(m._summary.partial)i=!0}else u(m)}let p=new TextDecoder,g="";for await(let h of n.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
4
|
-
`))!==-1)f(g.slice(0,m)),g=g.slice(m+1)}g+=p.decode();let k=g.trim();if(k.length>0)f(k);let S=await n.exited;if(S!==0){if(!c){let h=(await new Response(n.stderr).text()).trim();throw Error(`ulog decode failed (exit ${S})${h?`: ${h}`:""}`)}i=!0}if(!c)i=!0;if(i)o=a;let y={};for(let[h,m]of r)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of r)if(s[h]===void 0)s[h]=m.rows.length;return{partial:i,decodedUntil:o,tables:y,messageCounts:s}}var rn,sn;var xe=M(()=>{te();rn=nn(new URL("./ulog.py",import.meta.url)),sn=new Set(["timestamp","timestamp_sample"])});import{existsSync as Le,readFileSync as ln}from"fs";import{mkdtemp as un,rm as dn}from"fs/promises";import{tmpdir as fn}from"os";import{basename as re,join as se}from"path";function Ne(e){if(!e)return[];let t=se(e,".hydron","uav-format-converters.json");if(!Le(t))return[];try{let n=JSON.parse(ln(t,"utf8"));return Array.isArray(n.converters)?n.converters.filter((r)=>r&&r.match&&r.command):[]}catch{return[]}}function He(e,t){for(let n of t)try{if(new RegExp(n.match,"i").test(e))return n}catch{}return null}async function Ve(e,t){let n=await un(se(fn(),"uav-convert-")),r=re(e).replace(/\.[^.]+$/,""),s=se(n,r+(t.produces??".bin")),i=t.command.replaceAll("{input}",e).replaceAll("{output}",s),o=()=>dn(n,{recursive:!0,force:!0});try{let a=process.platform==="win32"?["cmd.exe","/d","/s","/c",i]:["bash","-lc",i],c=Bun.spawn(a,{stdout:"pipe",stderr:"pipe"}),l=await c.exited;if(l!==0){let u=(await new Response(c.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${l}) for ${re(e)}: ${u}`)}if(!Le(s))throw Error(`format converter produced no output for ${re(e)}`);return{out:s,cleanup:o}}catch(a){throw await o(),a}}var Be=()=>{};import{Database as mn}from"bun:sqlite";import{tmpdir as hn}from"os";import{join as pn}from"path";import{existsSync as je,unlinkSync as Ue}from"fs";function Xe(e){let t=pn(hn(),`uav-${e}-${process.pid}-${gn++}.sqlite`);try{if(je(t))Ue(t)}catch{}let n=new mn(t);return n.exec("PRAGMA page_size = 8192"),n.query("PRAGMA journal_mode = MEMORY").get(),n.exec("PRAGMA synchronous = OFF"),n.exec("PRAGMA temp_store = FILE"),n.exec("PRAGMA cache_size = -65536"),{db:n,cleanup(){try{n.close()}catch{}try{if(je(t))Ue(t)}catch{}}}}function oe(e){let t=new Map,n=new Map;return{table(r,s){if(t.has(r)||s.length===0)return;e.run(`CREATE TABLE ${ie(r)} (${s.map(ie).join(", ")})`);let i=s.map(()=>"?").join(", ");t.set(r,e.query(`INSERT INTO ${ie(r)} VALUES (${i})`)),n.set(r,s.length)},rows(r,s){let i=t.get(r),o=n.get(r);if(!i||o===void 0||s.length===0)return;let a=e.transaction((c)=>{for(let l of c){let u=Array(o);for(let f=0;f<o;f++){let p=l[f];u[f]=p===void 0?null:p}i.run(...u)}});for(let c=0;c<s.length;c+=Ge)a(s.slice(c,c+Ge))}}}function qe(e,t){let n=oe(e);for(let[r,s]of Object.entries(t.tables)){if(s.columns.length===0)continue;if(n.table(r,s.columns),s.rows.length)n.rows(r,s.rows)}}var gn=0,ie=(e)=>`"${e.replace(/"/g,'""')}"`,Ge=5000;var We=()=>{};async function j(e,t="flight",n){let r=He(e,Ne(n?.configDir));if(r){let{out:o,cleanup:a}=await Ve(e,r);try{return await j(o,t)}finally{await a()}}let{db:s,cleanup:i}=Xe(t);try{let o=e.toLowerCase();if(o.endsWith(".bin"))return{log:await Ie(e,oe(s),{retain:yn}),db:s,cleanup:i};let a;if(o.endsWith(".ulog"))a=await Oe(e);else if(o.endsWith(".tlog")||o.endsWith(".log"))a=await ne(e);else try{a=await Me(e)}catch{a=await ne(e)}return qe(s,a),{log:a,db:s,cleanup:i}}catch(o){throw i(),o}}var yn;var ae=M(()=>{Fe();$e();xe();Be();We();yn=new Set(["PARM","MSG","GPS","ERR","MODE"])});function ce(e,t){let n=e.tables.PARM;if(!n)return null;let r=n.columns.findIndex((o)=>o.toLowerCase()==="name"),s=n.columns.findIndex((o)=>o.toLowerCase()==="value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(String(o[r]).toLowerCase()===i){let a=Number(o[s]);return Number.isFinite(a)?a:null}return null}function bn(e){let t=e.tables.MSG;if(!t)return"";let n=t.columns.findIndex((r)=>/message|msg/i.test(r));if(n<0)return"";for(let r of t.rows){let s=String(r[n]??"");if(/Ardu(Copter|Plane|Sub|Rover)|PX4/i.test(s))return s}return""}function Je(e){let t=ce(e,"Q_ENABLE");if(t!==null&&t>=1||e.tables.QUIK||e.tables.AETR){if(e.tables.MOTB||ce(e,"FRAME_CLASS")!==null||e.tables.ARSP)return"vtol"}if(t!==null&&t>=1)return"vtol";let n=bn(e);if(/ArduPlane/i.test(n))return"fixedwing";if(/ArduCopter/i.test(n))return"multirotor";if(ce(e,"FRAME_CLASS")!==null)return"multirotor";if(e.tables.ARSP&&!e.tables.MOTB)return"fixedwing";if(e.tables.MOTB||e.tables.RATE)return"multirotor";return"unknown"}function X(e){return e===void 0||e==="multirotor"||e==="vtol"||e==="unknown"}function Ke(e){return e==="fixedwing"||e==="vtol"}function I(e){return`"${e.replace(/"/g,'""')}"`}function _(e,t){let n=e.db.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;return Number(r)}function D(e,t){try{let n=e.db.query(`PRAGMA table_info(${I(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function C(e,t,n){return D(e,t).has(n)}function Ye(e,t){for(let n of t)if(e.hasTable(n))return n;return null}function d(e,t,n){return{check:e,severity:"OK",value:null,threshold_used:null,ruleset_version:t.ruleset_version,verdict:"SKIP",tier:"system",...n?{detail:n}:{}}}function A(e){return{check:e.check,severity:e.failed?e.failSeverity:"OK",value:e.value,threshold_used:e.threshold_used,ruleset_version:e.thresholds.ruleset_version,verdict:e.failed?"FAIL":"PASS",tier:"system",...e.source?{source:e.source}:{},...e.detail?{detail:e.detail}:{}}}function Sn(e,t,n){let r=Object.values(e);if(t<=0||r.length===0)return"";let s=[...r].sort((l,u)=>u-l),i=s[0],o=s.length>1?s[1]:0;if(s.length>=2&&o>0&&i>=2*o)return" | cause: likely sensor/mounting alignment (one axis dominates)";let c=s.length>=2&&i<=1.5*(s[s.length-1]||i);if(n>0||c)return" | cause: likely mechanical degradation (props/bearings/frame)";return""}function Qe(e,t,n){let r=new Set;try{let o=e.query("SELECT name FROM sqlite_master WHERE type='table'").all();for(let a of o)r.add(a.name)}catch{}let s={db:e,thresholds:t,hasTable:(o)=>r.has(o),vehicleType:n?.vehicleType},i=[];for(let{id:o,run:a}of qn)try{i.push(a(s))}catch(c){let l=c instanceof Error?c.message:String(c);i.push(d(o,t,`check error: ${l}`))}return i}var _n=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("ERR"))return d("battery",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("battery",e.thresholds,"ERR present but Subsys/ECode columns absent");let n=t?.err_subsys??6,r=t?.err_ecode??1,s=_(e,`SELECT COUNT(*) FROM "ERR" WHERE "Subsys"=${n} AND "ECode"=${r}`)??0;return A({check:"battery",thresholds:e.thresholds,failed:s>0,failSeverity:"CRITICAL",value:s,threshold_used:0,source:t?.source,detail:s>0?`${s} battery failsafe ERR event(s) (Subsys=${n} ECode=${r})`:void 0})},wn=(e)=>{let t=e.thresholds.attitude;if(!e.hasTable("ATT"))return d("attitude",e.thresholds);for(let o of["DesRoll","Roll","DesPitch","Pitch"])if(!C(e,"ATT",o))return d("attitude",e.thresholds,`ATT missing column ${o}`);let n=t?.max_deg??5,r=_(e,'SELECT MAX(ABS("DesRoll"-"Roll")) FROM "ATT"'),s=_(e,'SELECT MAX(ABS("DesPitch"-"Pitch")) FROM "ATT"'),i=Math.max(r??0,s??0);return A({check:"attitude",thresholds:e.thresholds,failed:i>n,failSeverity:"HIGH",value:i,threshold_used:n,source:t?.source,detail:`peak roll err ${(r??0).toFixed(2)}\xB0, pitch err ${(s??0).toFixed(2)}\xB0`})},vn=(e)=>{let t=e.thresholds.altitude;if(!e.hasTable("CTUN"))return d("altitude",e.thresholds);if(!C(e,"CTUN","DAlt")||!C(e,"CTUN","Alt"))return d("altitude",e.thresholds,"CTUN missing DAlt/Alt columns");let n=t?.max_m??2,r=_(e,'SELECT MAX(ABS("DAlt"-"Alt")) FROM "CTUN"');return A({check:"altitude",thresholds:e.thresholds,failed:(r??0)>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},En=(e)=>{let t=e.thresholds.hover;if(!X(e.vehicleType))return d("hover",e.thresholds,`n/a for ${e.vehicleType} (no hover throttle)`);if(!e.hasTable("CTUN"))return d("hover",e.thresholds);if(!C(e,"CTUN","ThH"))return d("hover",e.thresholds,"CTUN missing ThH column");let n=t?.band??[0.25,0.75],[r,s]=n,i=_(e,'SELECT AVG("ThH") FROM "CTUN"'),o=i===null?!1:i<r||i>s;return A({check:"hover",thresholds:e.thresholds,failed:o,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`mean hover throttle ${(i??0).toFixed(3)} vs band [${r}, ${s}]`})},ze=2000,An=(e)=>{if(!X(e.vehicleType))return d("rcou",e.thresholds,`n/a for ${e.vehicleType} (control surfaces, not motor mix)`);if(!e.hasTable("RCOU"))return d("rcou",e.thresholds);let t=D(e,"RCOU"),n=[];for(let i=1;i<=8;i++)if(t.has(`C${i}`))n.push(`C${i}`);if(n.length===0)return d("rcou",e.thresholds,"RCOU has no C1..C8 channels");let r=-1/0,s=[];for(let i of n){let o=_(e,`SELECT MAX(${I(i)}) FROM "RCOU"`);if(o===null)continue;if(o>r)r=o;if(o>=ze)s.push(`${i}=${o}`)}if(r===-1/0)r=0;return A({check:"rcou",thresholds:e.thresholds,failed:s.length>0,failSeverity:"HIGH",value:r,threshold_used:ze,detail:s.length>0?`motor output(s) pegged at max: ${s.join(", ")}`:void 0})},le=1000,ue=2000,kn=(e)=>{if(!e.hasTable("RCIN"))return d("rcin",e.thresholds);if(!C(e,"RCIN","C3"))return d("rcin",e.thresholds,"RCIN missing C3 column");let t=_(e,'SELECT MIN("C3") FROM "RCIN"'),n=_(e,'SELECT MAX("C3") FROM "RCIN"'),r=t!==null&&t<le||n!==null&&n>ue,s=n;if(t!==null&&t<le)s=t;return A({check:"rcin",thresholds:e.thresholds,failed:r,failSeverity:"HIGH",value:s,threshold_used:ue,detail:`RCIN C3 range [${t??"\u2014"}, ${n??"\u2014"}] vs [${le}, ${ue}]`})},Tn=(e)=>{let t=e.thresholds.vibration;if(!e.hasTable("VIBE"))return d("vibration",e.thresholds);let n=D(e,"VIBE"),r=["VibeX","VibeY","VibeZ"].filter((f)=>n.has(f));if(r.length===0)return d("vibration",e.thresholds,"VIBE has no VibeX/Y/Z columns");let s=t?.max_ms2??30,i={},o=-1/0;for(let f of r){let g=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`)??0;if(i[f]=g,g>o)o=g}if(o===-1/0)o=0;let a=["Clip","Clip0","Clip1","Clip2"].filter((f)=>n.has(f)),c=0;for(let f of a){let p=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`);if(p!==null&&p>c)c=p}let l=a.length>0?` | clipping MAX=${c}${c>0?" (CLIP EVENTS)":""}`:"",u=Sn(i,o,c);return A({check:"vibration",thresholds:e.thresholds,failed:o>=s,failSeverity:"HIGH",value:o,threshold_used:s,source:t?.source,detail:`peak vibe ${o} m/s\xB2 (axes ${r.join("/")})${l}${u}`})},Cn=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag",e.thresholds);if(!C(e,"MAG","Health"))return d("mag",e.thresholds,"MAG missing Health column");let n=t?.min??1,r=_(e,'SELECT MIN("Health") FROM "MAG"');return A({check:"mag",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},Rn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF3","NKF3"]);if(!n)return d("ekf",e.thresholds);let r=D(e,n),s=["IVN","IVE","IVD","IVT","IPN","IPE","IPD"].filter((a)=>r.has(a));if(s.length===0)return d("ekf",e.thresholds,`${n} has no IVN/IVE/IVD/IVT/IPN/IPE/IPD columns`);let i=t?.max_ratio??0.5,o=-1/0;for(let a of s){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM ${I(n)}`);if(c!==null&&c>o)o=c}if(o===-1/0)o=0;return A({check:"ekf",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak innovation ${o} (${n}: ${s.join("/")})`})},Mn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("min_cell_voltage",e.thresholds);if(!C(e,"BAT","Volt"))return d("min_cell_voltage",e.thresholds,"BAT missing Volt column");let n=t?.min_cell_v??3.3,r=_(e,'SELECT MAX("Volt") FROM "BAT"'),s=_(e,'SELECT MIN("Volt") FROM "BAT"');if(r===null||s===null||r<=0)return d("min_cell_voltage",e.thresholds,"BAT.Volt has no usable values");let i=Math.max(1,Math.round(r/4.2)),o=s/i;return A({check:"min_cell_voltage",thresholds:e.thresholds,failed:o<n,failSeverity:"CRITICAL",value:o,threshold_used:n,source:t?.source,detail:`${i}S pack (MAX pack ${r.toFixed(2)}V), min cell ${o.toFixed(3)}V vs floor ${n}V`})},In=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("voltage_sag",e.thresholds);if(!C(e,"BAT","VoltR")||!C(e,"BAT","Volt"))return d("voltage_sag",e.thresholds,"BAT missing VoltR/Volt columns");let n=t?.max_sag_v??2,r=_(e,'SELECT MAX("VoltR"-"Volt") FROM "BAT"');return A({check:"voltage_sag",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak sag ${(r??0).toFixed(2)}V (VoltR-Volt) vs ${n}V`})},Fn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("over_current",e.thresholds);if(!C(e,"BAT","Curr"))return d("over_current",e.thresholds,"BAT missing Curr column");let n=t?.max_current_a??200,r=_(e,'SELECT MAX("Curr") FROM "BAT"');return A({check:"over_current",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak current ${(r??0).toFixed(1)}A vs ${n}A`})},Pn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("internal_resistance",e.thresholds);if(!C(e,"BAT","Res"))return d("internal_resistance",e.thresholds,"BAT missing Res column");let n=_(e,'SELECT MAX("Res") FROM "BAT"');if(n===null||n===0)return d("internal_resistance",e.thresholds,"BAT.Res all zero/absent (not reported)");let r=t?.res_min_current_a??5,i=C(e,"BAT","Curr")?_(e,`SELECT MAX("Res") FROM "BAT" WHERE "Curr" >= ${r}`):n;if(i===null)return d("internal_resistance",e.thresholds,`no BAT samples at Curr \u2265 ${r} A \u2014 Res only valid under load (max raw ${n.toFixed(3)}\u03A9 is a low-current artifact)`);let o=t?.max_res_ohm??0.03;return A({check:"internal_resistance",thresholds:e.thresholds,failed:i>o,failSeverity:"HIGH",value:i,threshold_used:o,source:t?.source,detail:`peak internal resistance ${i.toFixed(4)}\u03A9 (at Curr \u2265 ${r} A) vs ${o}\u03A9`})},Dn=(e)=>{let t=e.thresholds.power;if(!e.hasTable("POWR"))return d("board_brownout",e.thresholds);if(!C(e,"POWR","Vcc"))return d("board_brownout",e.thresholds,"POWR missing Vcc column");let n=t?.min_vcc_v??4.5,r=_(e,'SELECT MIN("Vcc") FROM "POWR"');return A({check:"board_brownout",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"CRITICAL",value:r,threshold_used:n,source:t?.source,detail:`min board Vcc ${(r??0).toFixed(3)}V vs floor ${n}V`})},$n=(e)=>{let t=e.thresholds.rate;if(!e.hasTable("RATE"))return d("rate_tracking",e.thresholds);let n=D(e,"RATE"),s=[["RDes","R"],["PDes","P"],["YDes","Y"]].filter(([c,l])=>n.has(c)&&n.has(l));if(s.length===0)return d("rate_tracking",e.thresholds,"RATE has no RDes/R, PDes/P, YDes/Y pairs");let i=t?.max_err_dps??50,o=-1/0,a="";for(let[c,l]of s){let u=_(e,`SELECT MAX(ABS(${I(c)}-${I(l)})) FROM "RATE"`);if(u!==null&&u>o)o=u,a=c.replace("Des","")}if(o===-1/0)o=0;return A({check:"rate_tracking",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak rate-tracking error ${o.toFixed(2)} deg/s (axis ${a||"?"}) vs ${i} deg/s`})},On=(e)=>{let t=e.thresholds.gps;if(!e.hasTable("GPA"))return d("gps_accuracy",e.thresholds);if(!C(e,"GPA","HAcc"))return d("gps_accuracy",e.thresholds,"GPA missing HAcc column");let n=t?.hacc_max_m??5,r=_(e,'SELECT MAX("HAcc") FROM "GPA"');return A({check:"gps_accuracy",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak horizontal accuracy ${(r??0).toFixed(2)}m vs ${n}m`})},xn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF4","NKF4"]);if(!n)return d("ekf_variance",e.thresholds);let r=D(e,n),s=["SV","SP","SH","SM"].filter((u)=>r.has(u));if(s.length===0)return d("ekf_variance",e.thresholds,`${n} has no SV/SP/SH/SM columns`);let i=t?.max_variance??1,o=-1/0,a="";for(let u of s){let f=_(e,`SELECT MAX(${I(u)}) FROM ${I(n)}`);if(f!==null&&f>o)o=f,a=u}if(o===-1/0)o=0;let c=r.has("FS")?_(e,`SELECT MAX("FS") FROM ${I(n)}`):null,l=c!==null&&c>0?` | EKF failsafe set (FS MAX=${c})`:"";return A({check:"ekf_variance",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak EKF variance ${o.toFixed(3)} (${n}: ${a||s.join("/")}) vs ${i}${l}`})},Ln=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag_offsets",e.thresholds);let n=D(e,"MAG"),r=["OfsX","OfsY","OfsZ"].filter((a)=>n.has(a));if(r.length===0)return d("mag_offsets",e.thresholds,"MAG has no OfsX/OfsY/OfsZ columns");let s=t?.max_offset??600,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM "MAG"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"mag_offsets",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak mag offset ${i.toFixed(0)} (${o||r.join("/")}) vs ${s}`})},Nn=(e)=>{let t=e.thresholds.esc;if(!e.hasTable("ESC"))return d("esc_health",e.thresholds);let n=D(e,"ESC"),r=["Temp","MotTemp"].filter((f)=>n.has(f));if(r.length===0&&!n.has("Err"))return d("esc_health",e.thresholds,"ESC has no Temp/MotTemp/Err columns");let s=t?.max_temp_c??90,i=-1/0,o="";for(let f of r){let p=_(e,`SELECT MAX(${I(f)}) FROM "ESC"`);if(p!==null&&p>i)i=p,o=f}if(i===-1/0)i=0;let a=n.has("Err")?_(e,'SELECT MAX("Err") FROM "ESC"')??0:0,c=r.length>0&&i>s,l=a>0,u=l?` | ESC Err MAX=${a}`:"";return A({check:"esc_health",thresholds:e.thresholds,failed:c||l,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak ESC temp ${i.toFixed(1)}\xB0C (${o||"n/a"}) vs ${s}\xB0C${u}`})},Hn=(e)=>{if(!X(e.vehicleType))return d("thrust_margin",e.thresholds,`n/a for ${e.vehicleType} (lift/T:W is a rotorcraft metric)`);if(!e.hasTable("MOTB"))return d("thrust_margin",e.thresholds);let t=D(e,"MOTB");if(!t.has("FailFlags")&&!(t.has("ThrOut")&&t.has("LiftMax")))return d("thrust_margin",e.thresholds,"MOTB missing FailFlags and ThrOut/LiftMax columns");let n=t.has("FailFlags")?_(e,'SELECT MAX("FailFlags") FROM "MOTB"')??0:0,r=null;if(t.has("ThrOut")&&t.has("LiftMax")){let a=_(e,'SELECT AVG("ThrOut") FROM "MOTB"'),c=_(e,'SELECT AVG("LiftMax") FROM "MOTB"');if(a!==null&&c!==null&&c>0)r=a/c}let s=r!==null&&r>0.5,i=n>0,o=`MOTB FailFlags MAX=${n}`+(r!==null?`, mean ThrOut/LiftMax ${r.toFixed(2)} (low-margin > 0.5)`:"")+(i?" \u2014 THRUST-LOSS flagged":s?" \u2014 low thrust margin":"");return A({check:"thrust_margin",thresholds:e.thresholds,failed:i||s,failSeverity:"HIGH",value:r,threshold_used:0.5,detail:o})},Vn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_health",e.thresholds);let n=D(e,"IMU"),r=["EG","EA"].filter((a)=>n.has(a));if(r.length===0)return d("imu_health",e.thresholds,"IMU has no EG/EA error-count columns");let s=t?.max_err??0,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(${I(a)}) FROM "IMU"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"imu_health",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`max IMU error count ${i} (${o||r.join("/")}) vs ${s}`})},Bn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_consistency",e.thresholds);let n=D(e,"IMU");if(!n.has("I"))return d("imu_consistency",e.thresholds,"IMU has no instance column I");let r=["AccX","AccY","AccZ"].filter((b)=>n.has(b)),s=["GyrX","GyrY","GyrZ"].filter((b)=>n.has(b));if(r.length===0&&s.length===0)return d("imu_consistency",e.thresholds,"IMU has no Acc*/Gyr* columns");let i=[...r,...s].map((b)=>`AVG(${I(b)}) ${I(b)}`).join(", "),o=e.db.query(`SELECT "I" AS "I", ${i} FROM "IMU" GROUP BY "I"`).all();if(o.length<2)return d("imu_consistency",e.thresholds,`only ${o.length} IMU instance \u2014 nothing to cross-check`);let a=(b)=>{let w=o.map((E)=>Number(E[b])).filter((E)=>Number.isFinite(E));return w.length>=2?Math.max(...w)-Math.min(...w):0},c=0,l="";for(let b of r){let w=a(b);if(w>c)c=w,l=b}let u=0,f="";for(let b of s){let w=a(b);if(w>u)u=w,f=b}let p=t?.accel_consistency_max??0.7,g=t?.gyro_consistency_max??0.3,k=c>p,S=u>g,y=k||S,h=c/p>=u/g?c:u,m=c/p>=u/g?p:g,v=y?`INCONSISTENT \u2014 ${k?`accel ${l} spread ${c.toFixed(3)} m/s\xB2 > ${p}`:""}${k&&S?"; ":""}${S?`gyro ${f} spread ${u.toFixed(3)} rad/s > ${g}`:""}`:`IMUs consistent \u2014 max inter-instance bias spread: accel ${c.toFixed(3)} m/s\xB2 (<${p}), gyro ${u.toFixed(3)} rad/s (<${g}); relative differences between instances are within healthy tolerance`;return A({check:"imu_consistency",thresholds:e.thresholds,failed:y,failSeverity:"HIGH",value:h,threshold_used:m,source:{kind:"rule-of-thumb",ref:"IMU inconsistency tolerance (~ArduPilot arming limits)"},detail:v})},jn=(e)=>{if(!e.hasTable("ERR"))return d("err_events",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("err_events",e.thresholds,"ERR present but Subsys/ECode columns absent");let t=e.thresholds.battery?.err_subsys??6,n=e.db.query(`SELECT "Subsys" AS subsys, "ECode" AS ecode, COUNT(*) AS n FROM "ERR" WHERE "ECode" <> 0 AND "Subsys" <> ${t} GROUP BY "Subsys", "ECode" ORDER BY "Subsys", "ECode"`).all(),r=0,s=[];for(let i of n)r+=Number(i.n),s.push(`Subsys=${i.subsys} ECode=${i.ecode} \xD7${i.n}`);return A({check:"err_events",thresholds:e.thresholds,failed:r>0,failSeverity:"HIGH",value:r,threshold_used:0,detail:r>0?`${r} non-battery ERR event(s): ${s.join(", ")}`:"no non-battery ERR events"})},Un,Gn=(e)=>{if(!e.hasTable("MODE"))return d("mode_changes",e.thresholds);if(!C(e,"MODE","ModeNum"))return d("mode_changes",e.thresholds,"MODE missing ModeNum column");let t=e.db.query('SELECT "ModeNum" AS modenum FROM "MODE"').all(),n=t.length,r=n>0?n-1:0,s=new Map,i=!1;for(let a of t){let c=Number(a.modenum);if(s.set(c,(s.get(c)??0)+1),Un.has(c))i=!0}let o=[...s.entries()].sort((a,c)=>a[0]-c[0]).map(([a,c])=>`Mode${a}\xD7${c}`).join(", ");return A({check:"mode_changes",thresholds:e.thresholds,failed:i,failSeverity:"HIGH",value:r,threshold_used:0,detail:`${r} mode change(s); timeline: ${o||"\u2014"}`+(i?" \u2014 emergency mode (RTL/LAND) entered":"")})},Xn=(e)=>{let t=e.thresholds.airspeed;if(!Ke(e.vehicleType))return d("airspeed",e.thresholds,`n/a for ${e.vehicleType} (no fixed-wing airspeed)`);if(!e.hasTable("ARSP"))return d("airspeed",e.thresholds,"no ARSP (airspeed) data");if(!C(e,"ARSP","Airspeed"))return d("airspeed",e.thresholds,"ARSP missing Airspeed column");let n=t?.stall_min_ms??8,r={kind:"rule-of-thumb",ref:"default stall floor"};if(e.hasTable("PARM")){let i=_(e,`SELECT "Value" FROM "PARM" WHERE "Name"='ARSPD_FBW_MIN' LIMIT 1`);if(i!==null&&i>0)n=i,r={kind:"datasheet",ref:"ARSPD_FBW_MIN"}}let s=_(e,'SELECT MIN("Airspeed") FROM "ARSP" WHERE "Airspeed" > 2');if(s===null)return d("airspeed",e.thresholds,"no airborne airspeed samples");return A({check:"airspeed",thresholds:e.thresholds,failed:s<n,failSeverity:"HIGH",value:s,threshold_used:n,source:r,detail:`min in-flight airspeed ${s.toFixed(1)} m/s vs stall floor ${n} m/s`})},qn;var Ze=M(()=>{Un=new Set([6,9]),qn=[{id:"battery",run:_n},{id:"min_cell_voltage",run:Mn},{id:"voltage_sag",run:In},{id:"over_current",run:Fn},{id:"internal_resistance",run:Pn},{id:"board_brownout",run:Dn},{id:"attitude",run:wn},{id:"rate_tracking",run:$n},{id:"altitude",run:vn},{id:"hover",run:En},{id:"rcou",run:An},{id:"rcin",run:kn},{id:"thrust_margin",run:Hn},{id:"vibration",run:Tn},{id:"imu_health",run:Vn},{id:"imu_consistency",run:Bn},{id:"mag",run:Cn},{id:"mag_offsets",run:Ln},{id:"gps_accuracy",run:On},{id:"ekf",run:Rn},{id:"ekf_variance",run:xn},{id:"esc_health",run:Nn},{id:"airspeed",run:Xn},{id:"err_events",run:jn},{id:"mode_changes",run:Gn}]});import{existsSync as Wn,readFileSync as Jn}from"fs";import{dirname as Kn,join as de}from"path";import{fileURLToPath as zn}from"url";function nt(e){if(e){let t=de(e,".hydron","apm-params.json"),n=tt(t);if(n&&n.size>0)return n}for(let t of Yn){let n=tt(t);if(n)return n}return new Map}function rt(e,t){return t.get(e.toUpperCase())}function tt(e){if(!Wn(e))return;try{let t=Jn(e,"utf8"),n=JSON.parse(t);if(!n||typeof n!=="object")return;let r=new Map;for(let[s,i]of Object.entries(n)){if(!s||s.startsWith("_")||typeof i!=="object"||i===null)continue;let o={name:s};if(typeof i.min==="number"&&Number.isFinite(i.min))o.min=i.min;if(typeof i.max==="number"&&Number.isFinite(i.max))o.max=i.max;if(typeof i.units==="string"&&i.units)o.units=i.units;r.set(s.toUpperCase(),o)}return r}catch{return}}var et,Yn;var st=M(()=>{et=Kn(zn(import.meta.url)),Yn=[de(et,"..","data","apm-params.json"),de(et,"..","..","data","apm-params.json")]});import{existsSync as Qn,readFileSync as Zn}from"fs";import{join as er}from"path";function it(){return{ruleset_version:"v1",safety:{ARMING_CHECK:{min:1},FS_THR_ENABLE:{min:1},FENCE_ENABLE:{min:1}},range:{INS_GYRO_FILTER:{min:5,max:80,severity:"HIGH"},ATC_RAT_RLL_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_PIT_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_YAW_P:{min:0,max:1,severity:"HIGH"},MOT_SPIN_ARM:{min:0,max:0.2,severity:"HIGH"},MOT_SPIN_MIN:{min:0,max:0.3,severity:"HIGH"},RTL_ALT:{min:200,max:1e4,severity:"HIGH"},WPNAV_SPEED:{min:50,max:2000,severity:"HIGH"}}}}function tr(e){let t=it(),n=er(e,".hydron","param-rules.yaml");if(!Qn(n))return t;try{let r=Zn(n,"utf8");return nr(t,r)}catch{return t}}function nr(e,t){let n={ruleset_version:e.ruleset_version,safety:{...e.safety},range:{...e.range}},r=null;for(let s of t.split(/\r?\n/)){let o=s.replace(/#.*$/,"").trim();if(!o||o.startsWith("-"))continue;let a=/^ruleset_version\s*:\s*(.+)$/.exec(o);if(a){n.ruleset_version=a[1].trim().replace(/^["']|["']$/g,""),r=null;continue}if(/^safety\s*:\s*$/.test(o)){r="safety";continue}if(/^range\s*:\s*$/.test(o)){r="range";continue}let c=/^([A-Za-z0-9_]+)\s*:\s*\{(.+)\}\s*$/.exec(o);if(c&&r){let l=c[1],u=rr(c[2]);if(r==="safety"){let f=u.min;if(typeof f==="number")n.safety[l]={min:f}}else{let{min:f,max:p,severity:g}=u;if(typeof f==="number"&&typeof p==="number")n.range[l]={min:f,max:p,severity:g==="CRITICAL"?"CRITICAL":"HIGH"}}}}return n}function rr(e){let t={};for(let n of e.split(",")){let r=/^\s*([A-Za-z0-9_]+)\s*:\s*(.+?)\s*$/.exec(n);if(!r)continue;let s=r[1],i=r[2].replace(/^["']|["']$/g,""),o=Number(i);t[s]=Number.isFinite(o)&&i!==""?o:i}return t}function sr(e){let t=new Map;for(let n of e)t.set(n.name.toUpperCase(),n.value);return t}function L(e){return{check:e.check,severity:e.severity,value:e.value,threshold_used:e.threshold_used,ruleset_version:e.ruleset_version,verdict:e.verdict,tier:"system",source:e.source,detail:e.detail}}function ot(e,t={}){let n=t.configDir?tr(t.configDir):it(),r=t.ruleset_version??n.ruleset_version,s=sr(e),i=nt(t.configDir);return[...ir(s,n,r),...or(s,r),...cr(s,n,r,i),...lr(e,null)]}function ir(e,t,n){let r=[],s={kind:"rule-of-thumb"},i=e.get("ARMING_CHECK");if(i===void 0)r.push(N("param.safety.arming",n,"ARMING_CHECK absent"));else{let u=i!==0;r.push(L({check:"param.safety.arming",severity:u?"OK":"CRITICAL",value:i,threshold_used:t.safety.ARMING_CHECK?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"arming checks enabled":"ARMING_CHECK=0 \u2014 ALL pre-arm safety checks are disabled",source:s}))}let o=e.get("BATT_LOW_VOLT"),a=e.get("BATT_CRT_VOLT");if(o===void 0&&a===void 0)r.push(N("param.safety.battery_failsafe",n,"BATT_LOW_VOLT/BATT_CRT_VOLT absent"));else{let u=(o??0)===0&&(a??0)===0;r.push(L({check:"param.safety.battery_failsafe",severity:u?"CRITICAL":"OK",value:u?0:a??o??0,threshold_used:0,verdict:u?"FAIL":"PASS",ruleset_version:n,detail:u?"battery failsafe not configured (BATT_LOW_VOLT and BATT_CRT_VOLT both 0)":"battery failsafe configured",source:s}))}let c=e.get("FS_THR_ENABLE");if(c===void 0)r.push(N("param.safety.radio_failsafe",n,"FS_THR_ENABLE absent"));else{let u=c!==0;r.push(L({check:"param.safety.radio_failsafe",severity:u?"OK":"HIGH",value:c,threshold_used:t.safety.FS_THR_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"radio failsafe enabled":"FS_THR_ENABLE=0 \u2014 radio/throttle failsafe is OFF",source:s}))}let l=e.get("FENCE_ENABLE");if(l===void 0)r.push(N("param.safety.fence",n,"FENCE_ENABLE absent"));else{let u=l!==0;r.push(L({check:"param.safety.fence",severity:u?"OK":"HIGH",value:l,threshold_used:t.safety.FENCE_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"geofence enabled":"FENCE_ENABLE=0 \u2014 geofence disabled (advisory)",source:s}))}return r}function or(e,t){let n=[],r={kind:"rule-of-thumb"},s=e.get("BATT_CRT_VOLT"),i=ar(e);if(s===void 0||s===0||i===null||i<=0)n.push(N("param.consistency.battery_cells",t,"BATT_CRT_VOLT and a cell-count source required"));else{let l=s/i,u=l>=3&&l<=3.7;n.push(L({check:"param.consistency.battery_cells",severity:u?"OK":"HIGH",value:fe(l,3),threshold_used:3,verdict:u?"PASS":"FAIL",ruleset_version:t,detail:u?`per-cell critical voltage ${fe(l,2)}V across ${i}S looks sane`:`per-cell critical voltage ${fe(l,2)}V (${i}S) outside [3.0,3.7] \u2014 cell count vs BATT_CRT_VOLT inconsistent`,source:r}))}let o=e.get("FRAME_CLASS"),a=e.get("FRAME_TYPE");if(o===void 0&&a===void 0)n.push(N("param.consistency.frame",t,"FRAME_CLASS/FRAME_TYPE absent"));else{let l=(o??0)!==0&&(a??0)!==0;n.push(L({check:"param.consistency.frame",severity:l?"OK":"HIGH",value:o??null,threshold_used:1,verdict:l?"PASS":"FAIL",ruleset_version:t,detail:l?`frame configured (CLASS=${o}, TYPE=${a})`:`frame not fully configured (CLASS=${o??"?"}, TYPE=${a??"?"}) \u2014 must be non-zero for a copter`,source:r}))}let c=e.get("INS_HNTCH_ENABLE");if(c===void 0)n.push(N("param.consistency.notch_filter",t,"INS_HNTCH_ENABLE absent"));else n.push(L({check:"param.consistency.notch_filter",severity:"OK",value:c,threshold_used:null,verdict:"PASS",ruleset_version:t,detail:c===0?"harmonic notch filter disabled (INS_HNTCH_ENABLE=0) \u2014 advisory; tune if vibration is high":"harmonic notch filter enabled",source:r}));return n}function ar(e){for(let n of["BATT_CELLS","BATT_N_CELLS","BATT_CELL_COUNT"]){let r=e.get(n);if(r!==void 0&&r>0)return Math.round(r)}let t=e.get("BATT_ARM_VOLT");if(t!==void 0&&t>0)return Math.round(t/3.6);return null}function cr(e,t,n,r){let s=[];for(let[i,o]of Object.entries(t.range)){let a=e.get(i.toUpperCase()),c=`param.range.${i}`;if(a===void 0){s.push(N(c,n,`${i} absent`));continue}let l=rt(i,r),u=l!==void 0&&(typeof l.min==="number"||typeof l.max==="number"),f=u&&typeof l.min==="number"?Math.max(o.min,l.min):o.min,p=u&&typeof l.max==="number"?Math.min(o.max,l.max):o.max,g=u&&typeof l.min==="number"?l.min:o.min,k=u&&typeof l.max==="number"?l.max:o.max,S=u?{kind:"datasheet",ref:"apm.pdef.xml"}:{kind:"tuned"},y=a>=f&&a<=p;s.push(L({check:c,severity:y?"OK":o.severity,value:a,threshold_used:y?k:a<f?g:k,verdict:y?"PASS":"FAIL",ruleset_version:n,detail:y?`${i}=${a} within [${g},${k}]${u?" (apm.pdef.xml)":""}`:`${i}=${a} outside [${g},${k}]${u?" (apm.pdef.xml)":""}`,source:S}))}return s}function lr(e,t){return[]}function N(e,t,n){return L({check:e,severity:"OK",value:null,threshold_used:null,verdict:"SKIP",ruleset_version:t,detail:n})}function fe(e,t){let n=10**t;return Math.round(e*n)/n}var at=M(()=>{st()});import{existsSync as ur,readFileSync as dr}from"fs";import{join as fr}from"path";function mr(){return{ruleset_version:"v1",vibration:{field:"VibeX|VibeY|VibeZ",max_ms2:30,source:{kind:"rule-of-thumb"}},clipping:{field:"Clip",max:0},battery:{err_subsys:6,err_ecode:1,min_cell_v:3.3,max_sag_v:2,max_current_a:200,max_res_ohm:0.03,res_min_current_a:5,source:{kind:"rule-of-thumb"}},attitude:{fields:"DesRoll-Roll,DesPitch-Pitch",max_deg:5,window_samples:10},altitude:{field:"DAlt-Alt",max_m:2},hover:{field:"ThH",band:[0.25,0.75]},ekf:{fields:"IVN,IVE,IVD",max_ratio:0.5,max_variance:1},mag:{field:"Health",min:1,late_align_s:30,max_offset:600},gps:{field:"NSats",min:6,hdop_max:2,hacc_max_m:5},power:{min_vcc_v:4.5,source:{kind:"rule-of-thumb"}},rate:{max_err_dps:50,source:{kind:"rule-of-thumb"}},esc:{max_temp_c:90,source:{kind:"rule-of-thumb"}},imu:{max_err:0,accel_consistency_max:0.7,gyro_consistency_max:0.3,source:{kind:"rule-of-thumb"}},airspeed:{stall_min_ms:8,source:{kind:"rule-of-thumb"}}}}function lt(e){let t=mr(),n=fr(e,".hydron","uav-thresholds.yaml");if(!ur(n))return t;try{let r=hr(dr(n,"utf8"));return ut(t,r)}catch{return t}}function ut(e,t){let n={...e};for(let[r,s]of Object.entries(t)){let i=n[r];if(s&&typeof s==="object"&&!Array.isArray(s)&&i&&typeof i==="object"&&!Array.isArray(i))n[r]=ut(i,s);else n[r]=s}return n}function ct(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let s=e[r];if(s==="'"&&!n)t=!t;else if(s==='"'&&!t)n=!n;else if(s==="#"&&!t&&!n)return e.slice(0,r)}return e}function dt(e,t){let n=[],r=0,s=!1,i=!1,o=0;for(let a=0;a<e.length;a++){let c=e[a];if(c==="'"&&!i)s=!s;else if(c==='"'&&!s)i=!i;else if(!s&&!i){if(c==="["||c==="{")r++;else if(c==="]"||c==="}")r--;else if(c===t&&r===0)n.push(e.slice(o,a)),o=a+1}}return n.push(e.slice(o)),n}function q(e){let t=e.trim();if(t==="")return"";if(/^-?\d+(\.\d+)?$/.test(t))return Number(t);if(t==="true")return!0;if(t==="false")return!1;if(t.startsWith("[")&&t.endsWith("]")){let n=t.slice(1,-1).trim();return n?dt(n,",").map(q):[]}if(t.startsWith("{")&&t.endsWith("}"))return ft(t);return t.replace(/^["']|["']$/g,"")}function ft(e){let t=e.trim().replace(/^\{/,"").replace(/\}$/,""),n={};for(let r of dt(t,",")){let s=r.indexOf(":");if(s<0)continue;let i=r.slice(0,s).trim().replace(/^["']|["']$/g,"");if(i)n[i]=q(r.slice(s+1))}return n}function hr(e){let t={},n=e.split(/\r?\n/),r=0;while(r<n.length){let s=ct(n[r]);if(r++,!s.trim()||/^\s/.test(s))continue;let i=/^([A-Za-z0-9_]+):\s*(.*)$/.exec(s);if(!i)continue;let o=i[1],a=i[2].trim();if(a.startsWith("{"))t[o]=ft(a);else if(a!=="")t[o]=q(a);else{let c={};while(r<n.length){let l=ct(n[r]);if(!l.trim()){r++;continue}if(!/^\s/.test(l))break;r++;let u=/^\s+([A-Za-z0-9_]+):\s*(.*)$/.exec(l);if(u&&u[2].trim()!=="")c[u[1]]=q(u[2])}t[o]=c}}return t}var mt=()=>{};function T(e,t){let n=t.toLowerCase();return e.columns.findIndex((r)=>r.toLowerCase()===n)}function x(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(typeof e==="string"){let t=Number(e);return Number.isFinite(t)?t:null}return null}function pr(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e.trim()))try{return BigInt(e.trim())}catch{return null}return null}function H(e){if(e===null||e===void 0)return null;if(typeof e==="string")return e;return String(e)}function W(e){return`"${e.replace(/"/g,'""')}"`}function ge(e,t){try{return!!e.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(t)}catch{return!1}}function ye(e,t){try{let n=e.query(`PRAGMA table_info(${W(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function J(e,t){try{let n=e.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;let s=typeof r==="bigint"?Number(r):Number(r);return Number.isFinite(s)?s:null}catch{return null}}function gr(e){for(let t of["ATT","GPS","VIBE","CTUN","IMU"])if(ge(e,t)&&ye(e,t).has("TimeUS")){let n=J(e,`SELECT COUNT(*) AS c FROM ${W(t)}`);if(n===null||n<=0)continue;let r=J(e,`SELECT (MAX("TimeUS") - MIN("TimeUS")) AS d FROM ${W(t)}`);if(r!==null)return r/1e6}return null}function yr(e){if(!ge(e,"VIBE"))return null;let t=ye(e,"VIBE"),n=["VibeX","VibeY","VibeZ"].filter((s)=>t.has(s));if(n.length===0)return null;let r=n.map((s)=>`SELECT MAX(${W(s)}) AS m FROM "VIBE"`).join(" UNION ALL ");return J(e,`SELECT MAX(m) AS m FROM (${r})`)}function br(e){if(!ge(e,"CTUN")||!ye(e,"CTUN").has("ThH"))return null;return J(e,'SELECT AVG("ThH") AS m FROM "CTUN"')}function me(e,t){let n=e.tables.PARM;if(!n)return null;let r=T(n,"Name"),s=T(n,"Value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(H(o[r])?.toLowerCase()===i)return x(o[s]);return null}function pe(e,t){let n=e.tables.MSG;if(!n)return null;let r=T(n,"Message")>=0?T(n,"Message"):T(n,"Msg");if(r<0)return null;for(let s of n.rows){let i=H(s[r]);if(i&&t.test(i))return i}return null}function vr(e){let t=e.tables.MSG;if(!t)return null;let n=T(t,"Message")>=0?T(t,"Message"):T(t,"Msg");if(n<0)return null;for(let r of t.rows){let s=H(r[n]),i=s&&wr.exec(s.trim());if(i){let[,o,a,c,l]=i;return{id:`${a}${c}${l}`.toUpperCase(),name:`${o}-${a.toUpperCase()}`}}}return null}function Er(e){let t=vr(e),n=me(e,"SYSID_THISMAV"),r,s;if(t)r=t.id,s=t.name;else if(n!==null)r=`sysid-${n}`,s=pe(e,/ArduCopter|ArduPlane|ArduPilot|board/i)??r;else{let a=pe(e,/ArduCopter|ArduPlane|ArduPilot|ChibiOS|board/i);r=a??"unknown",s=a??r}let i,o=me(e,"Q_ENABLE");if(o!==null&&o>=1)i="QuadPlane";else{let a=me(e,"FRAME_CLASS");if(a!==null)i=_r[a]??`class_${a}`}return{kind:"airframe",external_id:r,attrs:{name:s,frame:i}}}function Ar(e){let t=e.tables.GPS;if(!t)return null;let n=T(t,"GWk"),r=T(t,"GMS");if(n<0||r<0)return null;let s=315964800000,i=18000,o=null;for(let c of t.rows){let l=x(c[n]),u=x(c[r]);if(l===null||u===null||l<=0)continue;let f=s+l*7*24*3600*1000+u-i;if(o===null||f<o)o=f}if(o===null)return null;let a=new Date(o);return Number.isNaN(a.getTime())?null:a.toISOString()}function kr(e,t,n){let r=pe(e,/ArduCopter|ArduPlane|ArduPilot/);return{kind:"analysis",source_hash:n,logged_at:Ar(e),attrs:{firmware:r??null,duration_s:gr(t),pilot_id:null,rc_id:null}}}function Tr(e){let t=e.tables.PARM;if(!t)return[];let n=T(t,"Name"),r=T(t,"Value");if(n<0||r<0)return[];let s=T(t,"Default"),i=[];for(let o of t.rows){let a=H(o[n]);if(!a)continue;let c=x(o[r]);if(c===null)continue;let l={name:a,value:c};if(s>=0){let u=x(o[s]);l.default=u}i.push(l)}return i}function he(e,t){let n=T(e,"TimeUS");if(n<0)return 0n;return pr(t[n])??0n}function Sr(e){let t=[],n=e.tables.ERR;if(n){let i=T(n,"Subsys"),o=T(n,"ECode");for(let a of n.rows)t.push({at:he(n,a),type:"ERR",payload:{Subsys:i>=0?x(a[i]):null,ECode:o>=0?x(a[o]):null}})}let r=e.tables.MODE;if(r){let i=T(r,"TimeUS");for(let o of r.rows){let a={};r.columns.forEach((c,l)=>{if(l===i)return;a[c]=x(o[l])??H(o[l])}),t.push({at:he(r,o),type:"MODE",payload:a})}}let s=e.tables.MSG;if(s){let i=T(s,"Message")>=0?T(s,"Message"):T(s,"Msg");for(let o of s.rows)t.push({at:he(s,o),type:"MSG",payload:{text:i>=0?H(o[i]):null}})}return t}function Cr(e,t){let n=[],r=yr(t);if(r!==null)n.push({name:"vibe_peak",value:r,unit:"m/s/s"});let s=e.tables.ERR;if(s){let o=T(s,"Subsys"),a=T(s,"ECode");if(o>=0&&a>=0){let c=0;for(let l of s.rows)if(x(l[o])===6&&x(l[a])===1)c++;n.push({name:"failsafe_count",value:c})}}let i=br(t);if(i!==null)n.push({name:"hover_thr",value:i});return n}function ht(e,t,n){return{entity:Er(e),episode:kr(e,t,n.sourceHash),params:Tr(e),events:Sr(e),measurements:Cr(e,t)}}var _r,wr;var pt=M(()=>{_r={0:"Undefined",1:"Quad",2:"Hexa",3:"Octa",4:"OctaQuad",5:"Y6",6:"Heli",7:"Tri",8:"SingleCopter",9:"CoaxCopter",10:"BiCopter",11:"Heli_Dual",12:"DodecaHexa",13:"HeliQuad",14:"Deca",15:"Scripting"};wr=/^([A-Za-z][A-Za-z0-9_+\-]*)\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\b/});import{mkdir as Rr,readFile as be,writeFile as yt,readdir as bt,stat as Mr}from"fs/promises";import{dirname as Us,join as V}from"path";function _t(e,t,n){return V(e,".hydron","observations",t,K(n))}function K(e){return e.replace(/[^A-Za-z0-9._-]/g,"_")||"unknown"}function Ir(e,t){return typeof t==="bigint"?t.toString():t}function wt(e){if(Array.isArray(e.events))e.events=e.events.map((t)=>{let n=t.at,r;if(typeof n==="bigint")r=n;else if(typeof n==="string"&&/^-?\d+$/.test(n))r=BigInt(n);else if(typeof n==="number")r=BigInt(Math.trunc(n));else r=0n;return{...t,at:r}});return e}function Fr(e){let t=e.findings??[],n=t.filter((o)=>o.verdict==="FAIL").length,r=t.filter((o)=>o.severity==="CRITICAL"&&o.verdict==="FAIL").length,s="OK";for(let o of t)if(gt[o.severity]>gt[s])s=o.severity;let i=(o)=>e.measurements?.find((a)=>a.name===o)?.value??null;return{source_hash:e.episode.source_hash,logged_at:e.episode.logged_at,ruleset_version:e.ruleset_version,anomalies:n,critical:r,vibe_peak:i("vibe_peak"),failsafe_count:i("failsafe_count"),worst_severity:s,...e.tags&&e.tags.length>0?{tags:e.tags}:{}}}async function Pr(e){let t;try{t=await be(e,"utf8")}catch{return[]}let n=[];for(let r of t.split(`
|
|
2
|
+
var M=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};function Ee(){let e=process.env.UAV_DECODE_MAX_CPU;if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0&&t<1?t:void 0}async function Ae(e,t){if(!t||e<=0)return;let n=Math.min(e*(1/t-1),250);if(n>=1)await Vt(n)}var Vt=(e)=>new Promise((t)=>setTimeout(t,e));var ke;var Te=M(()=>{ke={a:{kind:"str",width:64},b:{kind:"i8",width:1},B:{kind:"u8",width:1},h:{kind:"i16",width:2},H:{kind:"u16",width:2},i:{kind:"i32",width:4},I:{kind:"u32",width:4},f:{kind:"f32",width:4},d:{kind:"f64",width:8},n:{kind:"str",width:4},N:{kind:"str",width:16},Z:{kind:"str",width:64},c:{kind:"i16",width:2,scale:0.01},C:{kind:"u16",width:2,scale:0.01},e:{kind:"i32",width:4,scale:0.01},E:{kind:"u32",width:4,scale:0.01},L:{kind:"i32",width:4,scale:0.0000001},M:{kind:"u8",width:1},q:{kind:"i64",width:8},Q:{kind:"u64",width:8}}});import{open as Bt}from"fs/promises";function Xt(e){return(t,n)=>{let r="",s=n+e;for(let i=n;i<s;i++){let o=t.getUint8(i);if(o===0)break;r+=String.fromCharCode(o)}return r}}function qt(e){let t=e.scale;switch(e.kind){case"i8":return t===void 0?(n,r)=>n.getInt8(r):(n,r)=>n.getInt8(r)*t;case"u8":return t===void 0?(n,r)=>n.getUint8(r):(n,r)=>n.getUint8(r)*t;case"i16":return t===void 0?(n,r)=>n.getInt16(r,!0):(n,r)=>n.getInt16(r,!0)*t;case"u16":return t===void 0?(n,r)=>n.getUint16(r,!0):(n,r)=>n.getUint16(r,!0)*t;case"i32":return t===void 0?(n,r)=>n.getInt32(r,!0):(n,r)=>n.getInt32(r,!0)*t;case"u32":return t===void 0?(n,r)=>n.getUint32(r,!0):(n,r)=>n.getUint32(r,!0)*t;case"f32":return(n,r)=>n.getFloat32(r,!0);case"f64":return(n,r)=>n.getFloat64(r,!0);case"i64":return(n,r)=>n.getBigInt64(r,!0);case"u64":return(n,r)=>n.getBigUint64(r,!0);case"str":return Xt(e.width)}}function Wt(e,t){let n=[],r=[];for(let i of e){let o=ke[i];if(!o)return{readers:[],widths:[],ok:!1,timeIdx:-1};n.push(qt(o)),r.push(o.width)}let s=t.indexOf("TimeUS");return{readers:n,widths:r,ok:!0,timeIdx:s}}async function Ce(e,t,n){let r=n??Ee(),s=new Map,i={},o=!1,a=null,c=null,l=4194304,u=await Bt(e,"r");try{let f=Buffer.allocUnsafe(l),p=new Uint8Array(0),g=0,k=!1;while(!k){let{bytesRead:S}=await u.read(f,0,l,g);g+=S,k=S===0;let y;if(S===0)y=p;else if(p.length===0)y=f.subarray(0,S);else y=new Uint8Array(p.length+S),y.set(p,0),y.set(f.subarray(0,S),p.length);let h=new DataView(y.buffer,y.byteOffset,y.byteLength),m=y.length,v=k,b=performance.now(),w=0;while(w+3<=m){if(y[w]!==jt||y[w+1]!==Ut){w+=1;continue}let E=y[w+2],F=w+3;if(E===Gt){if(F+Se>m){if(v)o=!0;break}let O=y[F],ve=y[F+1],U=Z(y,F+2,4),$t=Z(y,F+6,16),Q=Z(y,F+22,64).split(",").filter((Ht)=>Ht.length>0),{readers:Ot,widths:xt,ok:Lt,timeIdx:Nt}=Wt($t,Q);s.set(O,{name:U,length:ve,columns:Q,ok:Lt,payloadLen:ve-3,readers:Ot,widths:xt,timeIdx:Nt}),t.onFmt(U,Q),i[U]=(i[U]??0)+1,w+=3+Se;continue}let R=s.get(E);if(R===void 0){w+=1;continue}let P=R.payloadLen;if(F+P>m){if(v)o=!0;break}if(i[R.name]=(i[R.name]??0)+1,!R.ok){w+=3+P;continue}let{readers:z,widths:Dt}=R,Y=Array(z.length),we=F;for(let O=0;O<z.length;O++)Y[O]=z[O](h,we),we+=Dt[O];if(t.onRow(R.name,Y),R.timeIdx>=0){let O=Y[R.timeIdx];if(typeof O==="bigint")c=O}w+=3+P}if(p=y.slice(w),await Ae(performance.now()-b,r),k)break}}finally{await u.close()}if(o)a=c;return{partial:o,decodedUntil:a,messageCounts:i}}function Re(e,t,n){let r=e[t];if(!r)e[t]={columns:n,rows:[]};else r.columns=n}async function Me(e){let t={},n=await Ce(e,{onFmt:(r,s)=>Re(t,r,s),onRow:(r,s)=>{t[r].rows.push(s)}});return{partial:n.partial,decodedUntil:n.decodedUntil,tables:t,messageCounts:n.messageCounts}}async function Ie(e,t,n={}){let r=n.retain??new Set,s=5000,i={},o=new Map,a=await Ce(e,{onFmt:(c,l)=>{if(Re(i,c,l),t.table(c,l),!o.has(c))o.set(c,[])},onRow:(c,l)=>{let u=o.get(c);if(u){if(u.push(l),u.length>=5000)t.rows(c,u),u.length=0}if(r.has(c))i[c].rows.push(l)}});for(let[c,l]of o)if(l.length)t.rows(c,l);return{partial:a.partial,decodedUntil:a.decodedUntil,tables:i,messageCounts:a.messageCounts}}function Z(e,t,n){let r="",s=t+n;for(let i=t;i<s;i++){let o=e[i];if(o===0)break;r+=String.fromCharCode(o)}return r}var jt=163,Ut=149,Gt=128,Se=86;var Fe=M(()=>{Te()});function Kt(){let e=process.env.UAV_PYTHON?.trim();if(e)return[[e]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function zt(e){try{return await Bun.spawn([...e,"-c","import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"],{stdout:"ignore",stderr:"ignore",stdin:"ignore",windowsHide:!0}).exited===0}catch{return!1}}async function Yt(){if(Pe)return ee;for(let e of Kt())if(await zt(e)){ee=e;break}return Pe=!0,ee}async function G(){let e=await Yt();if(!e)throw Error(Jt);return e}var Jt,ee=null,Pe=!1;var te=M(()=>{Jt="no working Python 3 interpreter found. Install Python >= 3.8 and make sure `python3` "+"(macOS/Linux) or `python` (Windows \u2014 tick \u201CAdd python.exe to PATH\u201D in the installer) runs "+"from a terminal, or set UAV_PYTHON to the interpreter's full path."});import{fileURLToPath as Qt}from"url";function De(e){return typeof e==="object"&&e!==null&&"_summary"in e}function tn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function ne(e){let t=await G();if(await Bun.spawn([...t,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited!==0)throw Error(`pymavlink not found \u2014 ${t.join(" ")} -m pip install pymavlink`);let r=Bun.spawn([...t,Zt,e],{stdout:"pipe",stderr:"pipe",windowsHide:!0}),s=new Map,i={},o=!1,a=null,c=null,l=!1;function u(h){let m=s.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},s.set(h,m);return m}function f(h){let m=h.t,v=u(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=en.has(E)?tn(R):R;if(w[F]=P,E==="TimeUS"&&typeof P==="bigint")c=P}v.rows.push(w)}let p=new TextDecoder,g="";for await(let h of r.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
3
|
+
`))!==-1){let v=g.slice(0,m);if(g=g.slice(m+1),v.length===0)continue;let b;try{b=JSON.parse(v)}catch{o=!0;continue}if(De(b)){l=!0;for(let[w,E]of Object.entries(b._summary.counts))i[w]=E;if(b._summary.partial)o=!0}else f(b)}}g+=p.decode();let k=g.trim();if(k.length>0)try{let h=JSON.parse(k);if(De(h)){l=!0;for(let[m,v]of Object.entries(h._summary.counts))i[m]=v;if(h._summary.partial)o=!0}else f(h)}catch{o=!0}let S=await r.exited;if(S!==0){if(!l){let h=(await new Response(r.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${S})${h?`: ${h}`:""}`)}o=!0}if(!l)o=!0;if(o)a=c;let y={};for(let[h,m]of s)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of s)if(i[h]===void 0)i[h]=m.rows.length;return{partial:o,decodedUntil:a,tables:y,messageCounts:i}}var Zt,en;var $e=M(()=>{te();Zt=Qt(new URL("./mavdump.py",import.meta.url)),en=new Set(["TimeUS","TimeMS"])});import{fileURLToPath as nn}from"url";function on(e){return typeof e==="object"&&e!==null&&"_summary"in e}function an(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function cn(e){let t=()=>Bun.spawn([...e,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited;if(await t()===0)return;if(await Bun.spawn([...e,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore",windowsHide:!0}).exited,await t()!==0)throw Error(`pyulog not found \u2014 ${e.join(" ")} -m pip install pyulog`)}async function Oe(e){let t=await G();await cn(t);let n=Bun.spawn([...t,rn,e],{stdout:"pipe",stderr:"pipe",windowsHide:!0}),r=new Map,s={},i=!1,o=null,a=null,c=!1;function l(h){let m=r.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},r.set(h,m);return m}function u(h){let m=h.t,v=l(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=sn.has(E)?an(R):R;if(w[F]=P,E==="timestamp"&&typeof P==="bigint")a=P}v.rows.push(w)}function f(h){if(h.length===0)return;let m;try{m=JSON.parse(h)}catch{i=!0;return}if(on(m)){c=!0;for(let[v,b]of Object.entries(m._summary.counts))s[v]=b;if(m._summary.partial)i=!0}else u(m)}let p=new TextDecoder,g="";for await(let h of n.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
4
|
+
`))!==-1)f(g.slice(0,m)),g=g.slice(m+1)}g+=p.decode();let k=g.trim();if(k.length>0)f(k);let S=await n.exited;if(S!==0){if(!c){let h=(await new Response(n.stderr).text()).trim();throw Error(`ulog decode failed (exit ${S})${h?`: ${h}`:""}`)}i=!0}if(!c)i=!0;if(i)o=a;let y={};for(let[h,m]of r)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of r)if(s[h]===void 0)s[h]=m.rows.length;return{partial:i,decodedUntil:o,tables:y,messageCounts:s}}var rn,sn;var xe=M(()=>{te();rn=nn(new URL("./ulog.py",import.meta.url)),sn=new Set(["timestamp","timestamp_sample"])});import{existsSync as Le,readFileSync as ln}from"fs";import{mkdtemp as un,rm as dn}from"fs/promises";import{tmpdir as fn}from"os";import{basename as re,join as se}from"path";function Ne(e){if(!e)return[];let t=se(e,".hydron","uav-format-converters.json");if(!Le(t))return[];try{let n=JSON.parse(ln(t,"utf8"));return Array.isArray(n.converters)?n.converters.filter((r)=>r&&r.match&&r.command):[]}catch{return[]}}function He(e,t){for(let n of t)try{if(new RegExp(n.match,"i").test(e))return n}catch{}return null}async function Ve(e,t){let n=await un(se(fn(),"uav-convert-")),r=re(e).replace(/\.[^.]+$/,""),s=se(n,r+(t.produces??".bin")),i=t.command.replaceAll("{input}",e).replaceAll("{output}",s),o=()=>dn(n,{recursive:!0,force:!0});try{let a=process.platform==="win32"?["cmd.exe","/d","/s","/c",i]:["bash","-lc",i],c=Bun.spawn(a,{stdout:"pipe",stderr:"pipe",windowsHide:!0}),l=await c.exited;if(l!==0){let u=(await new Response(c.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${l}) for ${re(e)}: ${u}`)}if(!Le(s))throw Error(`format converter produced no output for ${re(e)}`);return{out:s,cleanup:o}}catch(a){throw await o(),a}}var Be=()=>{};import{Database as mn}from"bun:sqlite";import{tmpdir as hn}from"os";import{join as pn}from"path";import{existsSync as je,unlinkSync as Ue}from"fs";function Xe(e){let t=pn(hn(),`uav-${e}-${process.pid}-${gn++}.sqlite`);try{if(je(t))Ue(t)}catch{}let n=new mn(t);return n.exec("PRAGMA page_size = 8192"),n.query("PRAGMA journal_mode = MEMORY").get(),n.exec("PRAGMA synchronous = OFF"),n.exec("PRAGMA temp_store = FILE"),n.exec("PRAGMA cache_size = -65536"),{db:n,cleanup(){try{n.close()}catch{}try{if(je(t))Ue(t)}catch{}}}}function oe(e){let t=new Map,n=new Map;return{table(r,s){if(t.has(r)||s.length===0)return;e.run(`CREATE TABLE ${ie(r)} (${s.map(ie).join(", ")})`);let i=s.map(()=>"?").join(", ");t.set(r,e.query(`INSERT INTO ${ie(r)} VALUES (${i})`)),n.set(r,s.length)},rows(r,s){let i=t.get(r),o=n.get(r);if(!i||o===void 0||s.length===0)return;let a=e.transaction((c)=>{for(let l of c){let u=Array(o);for(let f=0;f<o;f++){let p=l[f];u[f]=p===void 0?null:p}i.run(...u)}});for(let c=0;c<s.length;c+=Ge)a(s.slice(c,c+Ge))}}}function qe(e,t){let n=oe(e);for(let[r,s]of Object.entries(t.tables)){if(s.columns.length===0)continue;if(n.table(r,s.columns),s.rows.length)n.rows(r,s.rows)}}var gn=0,ie=(e)=>`"${e.replace(/"/g,'""')}"`,Ge=5000;var We=()=>{};async function j(e,t="flight",n){let r=He(e,Ne(n?.configDir));if(r){let{out:o,cleanup:a}=await Ve(e,r);try{return await j(o,t)}finally{await a()}}let{db:s,cleanup:i}=Xe(t);try{let o=e.toLowerCase();if(o.endsWith(".bin"))return{log:await Ie(e,oe(s),{retain:yn}),db:s,cleanup:i};let a;if(o.endsWith(".ulog"))a=await Oe(e);else if(o.endsWith(".tlog")||o.endsWith(".log"))a=await ne(e);else try{a=await Me(e)}catch{a=await ne(e)}return qe(s,a),{log:a,db:s,cleanup:i}}catch(o){throw i(),o}}var yn;var ae=M(()=>{Fe();$e();xe();Be();We();yn=new Set(["PARM","MSG","GPS","ERR","MODE"])});function ce(e,t){let n=e.tables.PARM;if(!n)return null;let r=n.columns.findIndex((o)=>o.toLowerCase()==="name"),s=n.columns.findIndex((o)=>o.toLowerCase()==="value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(String(o[r]).toLowerCase()===i){let a=Number(o[s]);return Number.isFinite(a)?a:null}return null}function bn(e){let t=e.tables.MSG;if(!t)return"";let n=t.columns.findIndex((r)=>/message|msg/i.test(r));if(n<0)return"";for(let r of t.rows){let s=String(r[n]??"");if(/Ardu(Copter|Plane|Sub|Rover)|PX4/i.test(s))return s}return""}function Je(e){let t=ce(e,"Q_ENABLE");if(t!==null&&t>=1||e.tables.QUIK||e.tables.AETR){if(e.tables.MOTB||ce(e,"FRAME_CLASS")!==null||e.tables.ARSP)return"vtol"}if(t!==null&&t>=1)return"vtol";let n=bn(e);if(/ArduPlane/i.test(n))return"fixedwing";if(/ArduCopter/i.test(n))return"multirotor";if(ce(e,"FRAME_CLASS")!==null)return"multirotor";if(e.tables.ARSP&&!e.tables.MOTB)return"fixedwing";if(e.tables.MOTB||e.tables.RATE)return"multirotor";return"unknown"}function X(e){return e===void 0||e==="multirotor"||e==="vtol"||e==="unknown"}function Ke(e){return e==="fixedwing"||e==="vtol"}function I(e){return`"${e.replace(/"/g,'""')}"`}function _(e,t){let n=e.db.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;return Number(r)}function D(e,t){try{let n=e.db.query(`PRAGMA table_info(${I(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function C(e,t,n){return D(e,t).has(n)}function Ye(e,t){for(let n of t)if(e.hasTable(n))return n;return null}function d(e,t,n){return{check:e,severity:"OK",value:null,threshold_used:null,ruleset_version:t.ruleset_version,verdict:"SKIP",tier:"system",...n?{detail:n}:{}}}function A(e){return{check:e.check,severity:e.failed?e.failSeverity:"OK",value:e.value,threshold_used:e.threshold_used,ruleset_version:e.thresholds.ruleset_version,verdict:e.failed?"FAIL":"PASS",tier:"system",...e.source?{source:e.source}:{},...e.detail?{detail:e.detail}:{}}}function Sn(e,t,n){let r=Object.values(e);if(t<=0||r.length===0)return"";let s=[...r].sort((l,u)=>u-l),i=s[0],o=s.length>1?s[1]:0;if(s.length>=2&&o>0&&i>=2*o)return" | cause: likely sensor/mounting alignment (one axis dominates)";let c=s.length>=2&&i<=1.5*(s[s.length-1]||i);if(n>0||c)return" | cause: likely mechanical degradation (props/bearings/frame)";return""}function Qe(e,t,n){let r=new Set;try{let o=e.query("SELECT name FROM sqlite_master WHERE type='table'").all();for(let a of o)r.add(a.name)}catch{}let s={db:e,thresholds:t,hasTable:(o)=>r.has(o),vehicleType:n?.vehicleType},i=[];for(let{id:o,run:a}of qn)try{i.push(a(s))}catch(c){let l=c instanceof Error?c.message:String(c);i.push(d(o,t,`check error: ${l}`))}return i}var _n=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("ERR"))return d("battery",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("battery",e.thresholds,"ERR present but Subsys/ECode columns absent");let n=t?.err_subsys??6,r=t?.err_ecode??1,s=_(e,`SELECT COUNT(*) FROM "ERR" WHERE "Subsys"=${n} AND "ECode"=${r}`)??0;return A({check:"battery",thresholds:e.thresholds,failed:s>0,failSeverity:"CRITICAL",value:s,threshold_used:0,source:t?.source,detail:s>0?`${s} battery failsafe ERR event(s) (Subsys=${n} ECode=${r})`:void 0})},wn=(e)=>{let t=e.thresholds.attitude;if(!e.hasTable("ATT"))return d("attitude",e.thresholds);for(let o of["DesRoll","Roll","DesPitch","Pitch"])if(!C(e,"ATT",o))return d("attitude",e.thresholds,`ATT missing column ${o}`);let n=t?.max_deg??5,r=_(e,'SELECT MAX(ABS("DesRoll"-"Roll")) FROM "ATT"'),s=_(e,'SELECT MAX(ABS("DesPitch"-"Pitch")) FROM "ATT"'),i=Math.max(r??0,s??0);return A({check:"attitude",thresholds:e.thresholds,failed:i>n,failSeverity:"HIGH",value:i,threshold_used:n,source:t?.source,detail:`peak roll err ${(r??0).toFixed(2)}\xB0, pitch err ${(s??0).toFixed(2)}\xB0`})},vn=(e)=>{let t=e.thresholds.altitude;if(!e.hasTable("CTUN"))return d("altitude",e.thresholds);if(!C(e,"CTUN","DAlt")||!C(e,"CTUN","Alt"))return d("altitude",e.thresholds,"CTUN missing DAlt/Alt columns");let n=t?.max_m??2,r=_(e,'SELECT MAX(ABS("DAlt"-"Alt")) FROM "CTUN"');return A({check:"altitude",thresholds:e.thresholds,failed:(r??0)>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},En=(e)=>{let t=e.thresholds.hover;if(!X(e.vehicleType))return d("hover",e.thresholds,`n/a for ${e.vehicleType} (no hover throttle)`);if(!e.hasTable("CTUN"))return d("hover",e.thresholds);if(!C(e,"CTUN","ThH"))return d("hover",e.thresholds,"CTUN missing ThH column");let n=t?.band??[0.25,0.75],[r,s]=n,i=_(e,'SELECT AVG("ThH") FROM "CTUN"'),o=i===null?!1:i<r||i>s;return A({check:"hover",thresholds:e.thresholds,failed:o,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`mean hover throttle ${(i??0).toFixed(3)} vs band [${r}, ${s}]`})},ze=2000,An=(e)=>{if(!X(e.vehicleType))return d("rcou",e.thresholds,`n/a for ${e.vehicleType} (control surfaces, not motor mix)`);if(!e.hasTable("RCOU"))return d("rcou",e.thresholds);let t=D(e,"RCOU"),n=[];for(let i=1;i<=8;i++)if(t.has(`C${i}`))n.push(`C${i}`);if(n.length===0)return d("rcou",e.thresholds,"RCOU has no C1..C8 channels");let r=-1/0,s=[];for(let i of n){let o=_(e,`SELECT MAX(${I(i)}) FROM "RCOU"`);if(o===null)continue;if(o>r)r=o;if(o>=ze)s.push(`${i}=${o}`)}if(r===-1/0)r=0;return A({check:"rcou",thresholds:e.thresholds,failed:s.length>0,failSeverity:"HIGH",value:r,threshold_used:ze,detail:s.length>0?`motor output(s) pegged at max: ${s.join(", ")}`:void 0})},le=1000,ue=2000,kn=(e)=>{if(!e.hasTable("RCIN"))return d("rcin",e.thresholds);if(!C(e,"RCIN","C3"))return d("rcin",e.thresholds,"RCIN missing C3 column");let t=_(e,'SELECT MIN("C3") FROM "RCIN"'),n=_(e,'SELECT MAX("C3") FROM "RCIN"'),r=t!==null&&t<le||n!==null&&n>ue,s=n;if(t!==null&&t<le)s=t;return A({check:"rcin",thresholds:e.thresholds,failed:r,failSeverity:"HIGH",value:s,threshold_used:ue,detail:`RCIN C3 range [${t??"\u2014"}, ${n??"\u2014"}] vs [${le}, ${ue}]`})},Tn=(e)=>{let t=e.thresholds.vibration;if(!e.hasTable("VIBE"))return d("vibration",e.thresholds);let n=D(e,"VIBE"),r=["VibeX","VibeY","VibeZ"].filter((f)=>n.has(f));if(r.length===0)return d("vibration",e.thresholds,"VIBE has no VibeX/Y/Z columns");let s=t?.max_ms2??30,i={},o=-1/0;for(let f of r){let g=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`)??0;if(i[f]=g,g>o)o=g}if(o===-1/0)o=0;let a=["Clip","Clip0","Clip1","Clip2"].filter((f)=>n.has(f)),c=0;for(let f of a){let p=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`);if(p!==null&&p>c)c=p}let l=a.length>0?` | clipping MAX=${c}${c>0?" (CLIP EVENTS)":""}`:"",u=Sn(i,o,c);return A({check:"vibration",thresholds:e.thresholds,failed:o>=s,failSeverity:"HIGH",value:o,threshold_used:s,source:t?.source,detail:`peak vibe ${o} m/s\xB2 (axes ${r.join("/")})${l}${u}`})},Cn=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag",e.thresholds);if(!C(e,"MAG","Health"))return d("mag",e.thresholds,"MAG missing Health column");let n=t?.min??1,r=_(e,'SELECT MIN("Health") FROM "MAG"');return A({check:"mag",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},Rn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF3","NKF3"]);if(!n)return d("ekf",e.thresholds);let r=D(e,n),s=["IVN","IVE","IVD","IVT","IPN","IPE","IPD"].filter((a)=>r.has(a));if(s.length===0)return d("ekf",e.thresholds,`${n} has no IVN/IVE/IVD/IVT/IPN/IPE/IPD columns`);let i=t?.max_ratio??0.5,o=-1/0;for(let a of s){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM ${I(n)}`);if(c!==null&&c>o)o=c}if(o===-1/0)o=0;return A({check:"ekf",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak innovation ${o} (${n}: ${s.join("/")})`})},Mn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("min_cell_voltage",e.thresholds);if(!C(e,"BAT","Volt"))return d("min_cell_voltage",e.thresholds,"BAT missing Volt column");let n=t?.min_cell_v??3.3,r=_(e,'SELECT MAX("Volt") FROM "BAT"'),s=_(e,'SELECT MIN("Volt") FROM "BAT"');if(r===null||s===null||r<=0)return d("min_cell_voltage",e.thresholds,"BAT.Volt has no usable values");let i=Math.max(1,Math.round(r/4.2)),o=s/i;return A({check:"min_cell_voltage",thresholds:e.thresholds,failed:o<n,failSeverity:"CRITICAL",value:o,threshold_used:n,source:t?.source,detail:`${i}S pack (MAX pack ${r.toFixed(2)}V), min cell ${o.toFixed(3)}V vs floor ${n}V`})},In=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("voltage_sag",e.thresholds);if(!C(e,"BAT","VoltR")||!C(e,"BAT","Volt"))return d("voltage_sag",e.thresholds,"BAT missing VoltR/Volt columns");let n=t?.max_sag_v??2,r=_(e,'SELECT MAX("VoltR"-"Volt") FROM "BAT"');return A({check:"voltage_sag",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak sag ${(r??0).toFixed(2)}V (VoltR-Volt) vs ${n}V`})},Fn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("over_current",e.thresholds);if(!C(e,"BAT","Curr"))return d("over_current",e.thresholds,"BAT missing Curr column");let n=t?.max_current_a??200,r=_(e,'SELECT MAX("Curr") FROM "BAT"');return A({check:"over_current",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak current ${(r??0).toFixed(1)}A vs ${n}A`})},Pn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("internal_resistance",e.thresholds);if(!C(e,"BAT","Res"))return d("internal_resistance",e.thresholds,"BAT missing Res column");let n=_(e,'SELECT MAX("Res") FROM "BAT"');if(n===null||n===0)return d("internal_resistance",e.thresholds,"BAT.Res all zero/absent (not reported)");let r=t?.res_min_current_a??5,i=C(e,"BAT","Curr")?_(e,`SELECT MAX("Res") FROM "BAT" WHERE "Curr" >= ${r}`):n;if(i===null)return d("internal_resistance",e.thresholds,`no BAT samples at Curr \u2265 ${r} A \u2014 Res only valid under load (max raw ${n.toFixed(3)}\u03A9 is a low-current artifact)`);let o=t?.max_res_ohm??0.03;return A({check:"internal_resistance",thresholds:e.thresholds,failed:i>o,failSeverity:"HIGH",value:i,threshold_used:o,source:t?.source,detail:`peak internal resistance ${i.toFixed(4)}\u03A9 (at Curr \u2265 ${r} A) vs ${o}\u03A9`})},Dn=(e)=>{let t=e.thresholds.power;if(!e.hasTable("POWR"))return d("board_brownout",e.thresholds);if(!C(e,"POWR","Vcc"))return d("board_brownout",e.thresholds,"POWR missing Vcc column");let n=t?.min_vcc_v??4.5,r=_(e,'SELECT MIN("Vcc") FROM "POWR"');return A({check:"board_brownout",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"CRITICAL",value:r,threshold_used:n,source:t?.source,detail:`min board Vcc ${(r??0).toFixed(3)}V vs floor ${n}V`})},$n=(e)=>{let t=e.thresholds.rate;if(!e.hasTable("RATE"))return d("rate_tracking",e.thresholds);let n=D(e,"RATE"),s=[["RDes","R"],["PDes","P"],["YDes","Y"]].filter(([c,l])=>n.has(c)&&n.has(l));if(s.length===0)return d("rate_tracking",e.thresholds,"RATE has no RDes/R, PDes/P, YDes/Y pairs");let i=t?.max_err_dps??50,o=-1/0,a="";for(let[c,l]of s){let u=_(e,`SELECT MAX(ABS(${I(c)}-${I(l)})) FROM "RATE"`);if(u!==null&&u>o)o=u,a=c.replace("Des","")}if(o===-1/0)o=0;return A({check:"rate_tracking",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak rate-tracking error ${o.toFixed(2)} deg/s (axis ${a||"?"}) vs ${i} deg/s`})},On=(e)=>{let t=e.thresholds.gps;if(!e.hasTable("GPA"))return d("gps_accuracy",e.thresholds);if(!C(e,"GPA","HAcc"))return d("gps_accuracy",e.thresholds,"GPA missing HAcc column");let n=t?.hacc_max_m??5,r=_(e,'SELECT MAX("HAcc") FROM "GPA"');return A({check:"gps_accuracy",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak horizontal accuracy ${(r??0).toFixed(2)}m vs ${n}m`})},xn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF4","NKF4"]);if(!n)return d("ekf_variance",e.thresholds);let r=D(e,n),s=["SV","SP","SH","SM"].filter((u)=>r.has(u));if(s.length===0)return d("ekf_variance",e.thresholds,`${n} has no SV/SP/SH/SM columns`);let i=t?.max_variance??1,o=-1/0,a="";for(let u of s){let f=_(e,`SELECT MAX(${I(u)}) FROM ${I(n)}`);if(f!==null&&f>o)o=f,a=u}if(o===-1/0)o=0;let c=r.has("FS")?_(e,`SELECT MAX("FS") FROM ${I(n)}`):null,l=c!==null&&c>0?` | EKF failsafe set (FS MAX=${c})`:"";return A({check:"ekf_variance",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak EKF variance ${o.toFixed(3)} (${n}: ${a||s.join("/")}) vs ${i}${l}`})},Ln=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag_offsets",e.thresholds);let n=D(e,"MAG"),r=["OfsX","OfsY","OfsZ"].filter((a)=>n.has(a));if(r.length===0)return d("mag_offsets",e.thresholds,"MAG has no OfsX/OfsY/OfsZ columns");let s=t?.max_offset??600,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM "MAG"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"mag_offsets",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak mag offset ${i.toFixed(0)} (${o||r.join("/")}) vs ${s}`})},Nn=(e)=>{let t=e.thresholds.esc;if(!e.hasTable("ESC"))return d("esc_health",e.thresholds);let n=D(e,"ESC"),r=["Temp","MotTemp"].filter((f)=>n.has(f));if(r.length===0&&!n.has("Err"))return d("esc_health",e.thresholds,"ESC has no Temp/MotTemp/Err columns");let s=t?.max_temp_c??90,i=-1/0,o="";for(let f of r){let p=_(e,`SELECT MAX(${I(f)}) FROM "ESC"`);if(p!==null&&p>i)i=p,o=f}if(i===-1/0)i=0;let a=n.has("Err")?_(e,'SELECT MAX("Err") FROM "ESC"')??0:0,c=r.length>0&&i>s,l=a>0,u=l?` | ESC Err MAX=${a}`:"";return A({check:"esc_health",thresholds:e.thresholds,failed:c||l,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak ESC temp ${i.toFixed(1)}\xB0C (${o||"n/a"}) vs ${s}\xB0C${u}`})},Hn=(e)=>{if(!X(e.vehicleType))return d("thrust_margin",e.thresholds,`n/a for ${e.vehicleType} (lift/T:W is a rotorcraft metric)`);if(!e.hasTable("MOTB"))return d("thrust_margin",e.thresholds);let t=D(e,"MOTB");if(!t.has("FailFlags")&&!(t.has("ThrOut")&&t.has("LiftMax")))return d("thrust_margin",e.thresholds,"MOTB missing FailFlags and ThrOut/LiftMax columns");let n=t.has("FailFlags")?_(e,'SELECT MAX("FailFlags") FROM "MOTB"')??0:0,r=null;if(t.has("ThrOut")&&t.has("LiftMax")){let a=_(e,'SELECT AVG("ThrOut") FROM "MOTB"'),c=_(e,'SELECT AVG("LiftMax") FROM "MOTB"');if(a!==null&&c!==null&&c>0)r=a/c}let s=r!==null&&r>0.5,i=n>0,o=`MOTB FailFlags MAX=${n}`+(r!==null?`, mean ThrOut/LiftMax ${r.toFixed(2)} (low-margin > 0.5)`:"")+(i?" \u2014 THRUST-LOSS flagged":s?" \u2014 low thrust margin":"");return A({check:"thrust_margin",thresholds:e.thresholds,failed:i||s,failSeverity:"HIGH",value:r,threshold_used:0.5,detail:o})},Vn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_health",e.thresholds);let n=D(e,"IMU"),r=["EG","EA"].filter((a)=>n.has(a));if(r.length===0)return d("imu_health",e.thresholds,"IMU has no EG/EA error-count columns");let s=t?.max_err??0,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(${I(a)}) FROM "IMU"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"imu_health",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`max IMU error count ${i} (${o||r.join("/")}) vs ${s}`})},Bn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_consistency",e.thresholds);let n=D(e,"IMU");if(!n.has("I"))return d("imu_consistency",e.thresholds,"IMU has no instance column I");let r=["AccX","AccY","AccZ"].filter((b)=>n.has(b)),s=["GyrX","GyrY","GyrZ"].filter((b)=>n.has(b));if(r.length===0&&s.length===0)return d("imu_consistency",e.thresholds,"IMU has no Acc*/Gyr* columns");let i=[...r,...s].map((b)=>`AVG(${I(b)}) ${I(b)}`).join(", "),o=e.db.query(`SELECT "I" AS "I", ${i} FROM "IMU" GROUP BY "I"`).all();if(o.length<2)return d("imu_consistency",e.thresholds,`only ${o.length} IMU instance \u2014 nothing to cross-check`);let a=(b)=>{let w=o.map((E)=>Number(E[b])).filter((E)=>Number.isFinite(E));return w.length>=2?Math.max(...w)-Math.min(...w):0},c=0,l="";for(let b of r){let w=a(b);if(w>c)c=w,l=b}let u=0,f="";for(let b of s){let w=a(b);if(w>u)u=w,f=b}let p=t?.accel_consistency_max??0.7,g=t?.gyro_consistency_max??0.3,k=c>p,S=u>g,y=k||S,h=c/p>=u/g?c:u,m=c/p>=u/g?p:g,v=y?`INCONSISTENT \u2014 ${k?`accel ${l} spread ${c.toFixed(3)} m/s\xB2 > ${p}`:""}${k&&S?"; ":""}${S?`gyro ${f} spread ${u.toFixed(3)} rad/s > ${g}`:""}`:`IMUs consistent \u2014 max inter-instance bias spread: accel ${c.toFixed(3)} m/s\xB2 (<${p}), gyro ${u.toFixed(3)} rad/s (<${g}); relative differences between instances are within healthy tolerance`;return A({check:"imu_consistency",thresholds:e.thresholds,failed:y,failSeverity:"HIGH",value:h,threshold_used:m,source:{kind:"rule-of-thumb",ref:"IMU inconsistency tolerance (~ArduPilot arming limits)"},detail:v})},jn=(e)=>{if(!e.hasTable("ERR"))return d("err_events",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("err_events",e.thresholds,"ERR present but Subsys/ECode columns absent");let t=e.thresholds.battery?.err_subsys??6,n=e.db.query(`SELECT "Subsys" AS subsys, "ECode" AS ecode, COUNT(*) AS n FROM "ERR" WHERE "ECode" <> 0 AND "Subsys" <> ${t} GROUP BY "Subsys", "ECode" ORDER BY "Subsys", "ECode"`).all(),r=0,s=[];for(let i of n)r+=Number(i.n),s.push(`Subsys=${i.subsys} ECode=${i.ecode} \xD7${i.n}`);return A({check:"err_events",thresholds:e.thresholds,failed:r>0,failSeverity:"HIGH",value:r,threshold_used:0,detail:r>0?`${r} non-battery ERR event(s): ${s.join(", ")}`:"no non-battery ERR events"})},Un,Gn=(e)=>{if(!e.hasTable("MODE"))return d("mode_changes",e.thresholds);if(!C(e,"MODE","ModeNum"))return d("mode_changes",e.thresholds,"MODE missing ModeNum column");let t=e.db.query('SELECT "ModeNum" AS modenum FROM "MODE"').all(),n=t.length,r=n>0?n-1:0,s=new Map,i=!1;for(let a of t){let c=Number(a.modenum);if(s.set(c,(s.get(c)??0)+1),Un.has(c))i=!0}let o=[...s.entries()].sort((a,c)=>a[0]-c[0]).map(([a,c])=>`Mode${a}\xD7${c}`).join(", ");return A({check:"mode_changes",thresholds:e.thresholds,failed:i,failSeverity:"HIGH",value:r,threshold_used:0,detail:`${r} mode change(s); timeline: ${o||"\u2014"}`+(i?" \u2014 emergency mode (RTL/LAND) entered":"")})},Xn=(e)=>{let t=e.thresholds.airspeed;if(!Ke(e.vehicleType))return d("airspeed",e.thresholds,`n/a for ${e.vehicleType} (no fixed-wing airspeed)`);if(!e.hasTable("ARSP"))return d("airspeed",e.thresholds,"no ARSP (airspeed) data");if(!C(e,"ARSP","Airspeed"))return d("airspeed",e.thresholds,"ARSP missing Airspeed column");let n=t?.stall_min_ms??8,r={kind:"rule-of-thumb",ref:"default stall floor"};if(e.hasTable("PARM")){let i=_(e,`SELECT "Value" FROM "PARM" WHERE "Name"='ARSPD_FBW_MIN' LIMIT 1`);if(i!==null&&i>0)n=i,r={kind:"datasheet",ref:"ARSPD_FBW_MIN"}}let s=_(e,'SELECT MIN("Airspeed") FROM "ARSP" WHERE "Airspeed" > 2');if(s===null)return d("airspeed",e.thresholds,"no airborne airspeed samples");return A({check:"airspeed",thresholds:e.thresholds,failed:s<n,failSeverity:"HIGH",value:s,threshold_used:n,source:r,detail:`min in-flight airspeed ${s.toFixed(1)} m/s vs stall floor ${n} m/s`})},qn;var Ze=M(()=>{Un=new Set([6,9]),qn=[{id:"battery",run:_n},{id:"min_cell_voltage",run:Mn},{id:"voltage_sag",run:In},{id:"over_current",run:Fn},{id:"internal_resistance",run:Pn},{id:"board_brownout",run:Dn},{id:"attitude",run:wn},{id:"rate_tracking",run:$n},{id:"altitude",run:vn},{id:"hover",run:En},{id:"rcou",run:An},{id:"rcin",run:kn},{id:"thrust_margin",run:Hn},{id:"vibration",run:Tn},{id:"imu_health",run:Vn},{id:"imu_consistency",run:Bn},{id:"mag",run:Cn},{id:"mag_offsets",run:Ln},{id:"gps_accuracy",run:On},{id:"ekf",run:Rn},{id:"ekf_variance",run:xn},{id:"esc_health",run:Nn},{id:"airspeed",run:Xn},{id:"err_events",run:jn},{id:"mode_changes",run:Gn}]});import{existsSync as Wn,readFileSync as Jn}from"fs";import{dirname as Kn,join as de}from"path";import{fileURLToPath as zn}from"url";function nt(e){if(e){let t=de(e,".hydron","apm-params.json"),n=tt(t);if(n&&n.size>0)return n}for(let t of Yn){let n=tt(t);if(n)return n}return new Map}function rt(e,t){return t.get(e.toUpperCase())}function tt(e){if(!Wn(e))return;try{let t=Jn(e,"utf8"),n=JSON.parse(t);if(!n||typeof n!=="object")return;let r=new Map;for(let[s,i]of Object.entries(n)){if(!s||s.startsWith("_")||typeof i!=="object"||i===null)continue;let o={name:s};if(typeof i.min==="number"&&Number.isFinite(i.min))o.min=i.min;if(typeof i.max==="number"&&Number.isFinite(i.max))o.max=i.max;if(typeof i.units==="string"&&i.units)o.units=i.units;r.set(s.toUpperCase(),o)}return r}catch{return}}var et,Yn;var st=M(()=>{et=Kn(zn(import.meta.url)),Yn=[de(et,"..","data","apm-params.json"),de(et,"..","..","data","apm-params.json")]});import{existsSync as Qn,readFileSync as Zn}from"fs";import{join as er}from"path";function it(){return{ruleset_version:"v1",safety:{ARMING_CHECK:{min:1},FS_THR_ENABLE:{min:1},FENCE_ENABLE:{min:1}},range:{INS_GYRO_FILTER:{min:5,max:80,severity:"HIGH"},ATC_RAT_RLL_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_PIT_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_YAW_P:{min:0,max:1,severity:"HIGH"},MOT_SPIN_ARM:{min:0,max:0.2,severity:"HIGH"},MOT_SPIN_MIN:{min:0,max:0.3,severity:"HIGH"},RTL_ALT:{min:200,max:1e4,severity:"HIGH"},WPNAV_SPEED:{min:50,max:2000,severity:"HIGH"}}}}function tr(e){let t=it(),n=er(e,".hydron","param-rules.yaml");if(!Qn(n))return t;try{let r=Zn(n,"utf8");return nr(t,r)}catch{return t}}function nr(e,t){let n={ruleset_version:e.ruleset_version,safety:{...e.safety},range:{...e.range}},r=null;for(let s of t.split(/\r?\n/)){let o=s.replace(/#.*$/,"").trim();if(!o||o.startsWith("-"))continue;let a=/^ruleset_version\s*:\s*(.+)$/.exec(o);if(a){n.ruleset_version=a[1].trim().replace(/^["']|["']$/g,""),r=null;continue}if(/^safety\s*:\s*$/.test(o)){r="safety";continue}if(/^range\s*:\s*$/.test(o)){r="range";continue}let c=/^([A-Za-z0-9_]+)\s*:\s*\{(.+)\}\s*$/.exec(o);if(c&&r){let l=c[1],u=rr(c[2]);if(r==="safety"){let f=u.min;if(typeof f==="number")n.safety[l]={min:f}}else{let{min:f,max:p,severity:g}=u;if(typeof f==="number"&&typeof p==="number")n.range[l]={min:f,max:p,severity:g==="CRITICAL"?"CRITICAL":"HIGH"}}}}return n}function rr(e){let t={};for(let n of e.split(",")){let r=/^\s*([A-Za-z0-9_]+)\s*:\s*(.+?)\s*$/.exec(n);if(!r)continue;let s=r[1],i=r[2].replace(/^["']|["']$/g,""),o=Number(i);t[s]=Number.isFinite(o)&&i!==""?o:i}return t}function sr(e){let t=new Map;for(let n of e)t.set(n.name.toUpperCase(),n.value);return t}function L(e){return{check:e.check,severity:e.severity,value:e.value,threshold_used:e.threshold_used,ruleset_version:e.ruleset_version,verdict:e.verdict,tier:"system",source:e.source,detail:e.detail}}function ot(e,t={}){let n=t.configDir?tr(t.configDir):it(),r=t.ruleset_version??n.ruleset_version,s=sr(e),i=nt(t.configDir);return[...ir(s,n,r),...or(s,r),...cr(s,n,r,i),...lr(e,null)]}function ir(e,t,n){let r=[],s={kind:"rule-of-thumb"},i=e.get("ARMING_CHECK");if(i===void 0)r.push(N("param.safety.arming",n,"ARMING_CHECK absent"));else{let u=i!==0;r.push(L({check:"param.safety.arming",severity:u?"OK":"CRITICAL",value:i,threshold_used:t.safety.ARMING_CHECK?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"arming checks enabled":"ARMING_CHECK=0 \u2014 ALL pre-arm safety checks are disabled",source:s}))}let o=e.get("BATT_LOW_VOLT"),a=e.get("BATT_CRT_VOLT");if(o===void 0&&a===void 0)r.push(N("param.safety.battery_failsafe",n,"BATT_LOW_VOLT/BATT_CRT_VOLT absent"));else{let u=(o??0)===0&&(a??0)===0;r.push(L({check:"param.safety.battery_failsafe",severity:u?"CRITICAL":"OK",value:u?0:a??o??0,threshold_used:0,verdict:u?"FAIL":"PASS",ruleset_version:n,detail:u?"battery failsafe not configured (BATT_LOW_VOLT and BATT_CRT_VOLT both 0)":"battery failsafe configured",source:s}))}let c=e.get("FS_THR_ENABLE");if(c===void 0)r.push(N("param.safety.radio_failsafe",n,"FS_THR_ENABLE absent"));else{let u=c!==0;r.push(L({check:"param.safety.radio_failsafe",severity:u?"OK":"HIGH",value:c,threshold_used:t.safety.FS_THR_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"radio failsafe enabled":"FS_THR_ENABLE=0 \u2014 radio/throttle failsafe is OFF",source:s}))}let l=e.get("FENCE_ENABLE");if(l===void 0)r.push(N("param.safety.fence",n,"FENCE_ENABLE absent"));else{let u=l!==0;r.push(L({check:"param.safety.fence",severity:u?"OK":"HIGH",value:l,threshold_used:t.safety.FENCE_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"geofence enabled":"FENCE_ENABLE=0 \u2014 geofence disabled (advisory)",source:s}))}return r}function or(e,t){let n=[],r={kind:"rule-of-thumb"},s=e.get("BATT_CRT_VOLT"),i=ar(e);if(s===void 0||s===0||i===null||i<=0)n.push(N("param.consistency.battery_cells",t,"BATT_CRT_VOLT and a cell-count source required"));else{let l=s/i,u=l>=3&&l<=3.7;n.push(L({check:"param.consistency.battery_cells",severity:u?"OK":"HIGH",value:fe(l,3),threshold_used:3,verdict:u?"PASS":"FAIL",ruleset_version:t,detail:u?`per-cell critical voltage ${fe(l,2)}V across ${i}S looks sane`:`per-cell critical voltage ${fe(l,2)}V (${i}S) outside [3.0,3.7] \u2014 cell count vs BATT_CRT_VOLT inconsistent`,source:r}))}let o=e.get("FRAME_CLASS"),a=e.get("FRAME_TYPE");if(o===void 0&&a===void 0)n.push(N("param.consistency.frame",t,"FRAME_CLASS/FRAME_TYPE absent"));else{let l=(o??0)!==0&&(a??0)!==0;n.push(L({check:"param.consistency.frame",severity:l?"OK":"HIGH",value:o??null,threshold_used:1,verdict:l?"PASS":"FAIL",ruleset_version:t,detail:l?`frame configured (CLASS=${o}, TYPE=${a})`:`frame not fully configured (CLASS=${o??"?"}, TYPE=${a??"?"}) \u2014 must be non-zero for a copter`,source:r}))}let c=e.get("INS_HNTCH_ENABLE");if(c===void 0)n.push(N("param.consistency.notch_filter",t,"INS_HNTCH_ENABLE absent"));else n.push(L({check:"param.consistency.notch_filter",severity:"OK",value:c,threshold_used:null,verdict:"PASS",ruleset_version:t,detail:c===0?"harmonic notch filter disabled (INS_HNTCH_ENABLE=0) \u2014 advisory; tune if vibration is high":"harmonic notch filter enabled",source:r}));return n}function ar(e){for(let n of["BATT_CELLS","BATT_N_CELLS","BATT_CELL_COUNT"]){let r=e.get(n);if(r!==void 0&&r>0)return Math.round(r)}let t=e.get("BATT_ARM_VOLT");if(t!==void 0&&t>0)return Math.round(t/3.6);return null}function cr(e,t,n,r){let s=[];for(let[i,o]of Object.entries(t.range)){let a=e.get(i.toUpperCase()),c=`param.range.${i}`;if(a===void 0){s.push(N(c,n,`${i} absent`));continue}let l=rt(i,r),u=l!==void 0&&(typeof l.min==="number"||typeof l.max==="number"),f=u&&typeof l.min==="number"?Math.max(o.min,l.min):o.min,p=u&&typeof l.max==="number"?Math.min(o.max,l.max):o.max,g=u&&typeof l.min==="number"?l.min:o.min,k=u&&typeof l.max==="number"?l.max:o.max,S=u?{kind:"datasheet",ref:"apm.pdef.xml"}:{kind:"tuned"},y=a>=f&&a<=p;s.push(L({check:c,severity:y?"OK":o.severity,value:a,threshold_used:y?k:a<f?g:k,verdict:y?"PASS":"FAIL",ruleset_version:n,detail:y?`${i}=${a} within [${g},${k}]${u?" (apm.pdef.xml)":""}`:`${i}=${a} outside [${g},${k}]${u?" (apm.pdef.xml)":""}`,source:S}))}return s}function lr(e,t){return[]}function N(e,t,n){return L({check:e,severity:"OK",value:null,threshold_used:null,verdict:"SKIP",ruleset_version:t,detail:n})}function fe(e,t){let n=10**t;return Math.round(e*n)/n}var at=M(()=>{st()});import{existsSync as ur,readFileSync as dr}from"fs";import{join as fr}from"path";function mr(){return{ruleset_version:"v1",vibration:{field:"VibeX|VibeY|VibeZ",max_ms2:30,source:{kind:"rule-of-thumb"}},clipping:{field:"Clip",max:0},battery:{err_subsys:6,err_ecode:1,min_cell_v:3.3,max_sag_v:2,max_current_a:200,max_res_ohm:0.03,res_min_current_a:5,source:{kind:"rule-of-thumb"}},attitude:{fields:"DesRoll-Roll,DesPitch-Pitch",max_deg:5,window_samples:10},altitude:{field:"DAlt-Alt",max_m:2},hover:{field:"ThH",band:[0.25,0.75]},ekf:{fields:"IVN,IVE,IVD",max_ratio:0.5,max_variance:1},mag:{field:"Health",min:1,late_align_s:30,max_offset:600},gps:{field:"NSats",min:6,hdop_max:2,hacc_max_m:5},power:{min_vcc_v:4.5,source:{kind:"rule-of-thumb"}},rate:{max_err_dps:50,source:{kind:"rule-of-thumb"}},esc:{max_temp_c:90,source:{kind:"rule-of-thumb"}},imu:{max_err:0,accel_consistency_max:0.7,gyro_consistency_max:0.3,source:{kind:"rule-of-thumb"}},airspeed:{stall_min_ms:8,source:{kind:"rule-of-thumb"}}}}function lt(e){let t=mr(),n=fr(e,".hydron","uav-thresholds.yaml");if(!ur(n))return t;try{let r=hr(dr(n,"utf8"));return ut(t,r)}catch{return t}}function ut(e,t){let n={...e};for(let[r,s]of Object.entries(t)){let i=n[r];if(s&&typeof s==="object"&&!Array.isArray(s)&&i&&typeof i==="object"&&!Array.isArray(i))n[r]=ut(i,s);else n[r]=s}return n}function ct(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let s=e[r];if(s==="'"&&!n)t=!t;else if(s==='"'&&!t)n=!n;else if(s==="#"&&!t&&!n)return e.slice(0,r)}return e}function dt(e,t){let n=[],r=0,s=!1,i=!1,o=0;for(let a=0;a<e.length;a++){let c=e[a];if(c==="'"&&!i)s=!s;else if(c==='"'&&!s)i=!i;else if(!s&&!i){if(c==="["||c==="{")r++;else if(c==="]"||c==="}")r--;else if(c===t&&r===0)n.push(e.slice(o,a)),o=a+1}}return n.push(e.slice(o)),n}function q(e){let t=e.trim();if(t==="")return"";if(/^-?\d+(\.\d+)?$/.test(t))return Number(t);if(t==="true")return!0;if(t==="false")return!1;if(t.startsWith("[")&&t.endsWith("]")){let n=t.slice(1,-1).trim();return n?dt(n,",").map(q):[]}if(t.startsWith("{")&&t.endsWith("}"))return ft(t);return t.replace(/^["']|["']$/g,"")}function ft(e){let t=e.trim().replace(/^\{/,"").replace(/\}$/,""),n={};for(let r of dt(t,",")){let s=r.indexOf(":");if(s<0)continue;let i=r.slice(0,s).trim().replace(/^["']|["']$/g,"");if(i)n[i]=q(r.slice(s+1))}return n}function hr(e){let t={},n=e.split(/\r?\n/),r=0;while(r<n.length){let s=ct(n[r]);if(r++,!s.trim()||/^\s/.test(s))continue;let i=/^([A-Za-z0-9_]+):\s*(.*)$/.exec(s);if(!i)continue;let o=i[1],a=i[2].trim();if(a.startsWith("{"))t[o]=ft(a);else if(a!=="")t[o]=q(a);else{let c={};while(r<n.length){let l=ct(n[r]);if(!l.trim()){r++;continue}if(!/^\s/.test(l))break;r++;let u=/^\s+([A-Za-z0-9_]+):\s*(.*)$/.exec(l);if(u&&u[2].trim()!=="")c[u[1]]=q(u[2])}t[o]=c}}return t}var mt=()=>{};function T(e,t){let n=t.toLowerCase();return e.columns.findIndex((r)=>r.toLowerCase()===n)}function x(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(typeof e==="string"){let t=Number(e);return Number.isFinite(t)?t:null}return null}function pr(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e.trim()))try{return BigInt(e.trim())}catch{return null}return null}function H(e){if(e===null||e===void 0)return null;if(typeof e==="string")return e;return String(e)}function W(e){return`"${e.replace(/"/g,'""')}"`}function ge(e,t){try{return!!e.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(t)}catch{return!1}}function ye(e,t){try{let n=e.query(`PRAGMA table_info(${W(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function J(e,t){try{let n=e.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;let s=typeof r==="bigint"?Number(r):Number(r);return Number.isFinite(s)?s:null}catch{return null}}function gr(e){for(let t of["ATT","GPS","VIBE","CTUN","IMU"])if(ge(e,t)&&ye(e,t).has("TimeUS")){let n=J(e,`SELECT COUNT(*) AS c FROM ${W(t)}`);if(n===null||n<=0)continue;let r=J(e,`SELECT (MAX("TimeUS") - MIN("TimeUS")) AS d FROM ${W(t)}`);if(r!==null)return r/1e6}return null}function yr(e){if(!ge(e,"VIBE"))return null;let t=ye(e,"VIBE"),n=["VibeX","VibeY","VibeZ"].filter((s)=>t.has(s));if(n.length===0)return null;let r=n.map((s)=>`SELECT MAX(${W(s)}) AS m FROM "VIBE"`).join(" UNION ALL ");return J(e,`SELECT MAX(m) AS m FROM (${r})`)}function br(e){if(!ge(e,"CTUN")||!ye(e,"CTUN").has("ThH"))return null;return J(e,'SELECT AVG("ThH") AS m FROM "CTUN"')}function me(e,t){let n=e.tables.PARM;if(!n)return null;let r=T(n,"Name"),s=T(n,"Value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(H(o[r])?.toLowerCase()===i)return x(o[s]);return null}function pe(e,t){let n=e.tables.MSG;if(!n)return null;let r=T(n,"Message")>=0?T(n,"Message"):T(n,"Msg");if(r<0)return null;for(let s of n.rows){let i=H(s[r]);if(i&&t.test(i))return i}return null}function vr(e){let t=e.tables.MSG;if(!t)return null;let n=T(t,"Message")>=0?T(t,"Message"):T(t,"Msg");if(n<0)return null;for(let r of t.rows){let s=H(r[n]),i=s&&wr.exec(s.trim());if(i){let[,o,a,c,l]=i;return{id:`${a}${c}${l}`.toUpperCase(),name:`${o}-${a.toUpperCase()}`}}}return null}function Er(e){let t=vr(e),n=me(e,"SYSID_THISMAV"),r,s;if(t)r=t.id,s=t.name;else if(n!==null)r=`sysid-${n}`,s=pe(e,/ArduCopter|ArduPlane|ArduPilot|board/i)??r;else{let a=pe(e,/ArduCopter|ArduPlane|ArduPilot|ChibiOS|board/i);r=a??"unknown",s=a??r}let i,o=me(e,"Q_ENABLE");if(o!==null&&o>=1)i="QuadPlane";else{let a=me(e,"FRAME_CLASS");if(a!==null)i=_r[a]??`class_${a}`}return{kind:"airframe",external_id:r,attrs:{name:s,frame:i}}}function Ar(e){let t=e.tables.GPS;if(!t)return null;let n=T(t,"GWk"),r=T(t,"GMS");if(n<0||r<0)return null;let s=315964800000,i=18000,o=null;for(let c of t.rows){let l=x(c[n]),u=x(c[r]);if(l===null||u===null||l<=0)continue;let f=s+l*7*24*3600*1000+u-i;if(o===null||f<o)o=f}if(o===null)return null;let a=new Date(o);return Number.isNaN(a.getTime())?null:a.toISOString()}function kr(e,t,n){let r=pe(e,/ArduCopter|ArduPlane|ArduPilot/);return{kind:"analysis",source_hash:n,logged_at:Ar(e),attrs:{firmware:r??null,duration_s:gr(t),pilot_id:null,rc_id:null}}}function Tr(e){let t=e.tables.PARM;if(!t)return[];let n=T(t,"Name"),r=T(t,"Value");if(n<0||r<0)return[];let s=T(t,"Default"),i=[];for(let o of t.rows){let a=H(o[n]);if(!a)continue;let c=x(o[r]);if(c===null)continue;let l={name:a,value:c};if(s>=0){let u=x(o[s]);l.default=u}i.push(l)}return i}function he(e,t){let n=T(e,"TimeUS");if(n<0)return 0n;return pr(t[n])??0n}function Sr(e){let t=[],n=e.tables.ERR;if(n){let i=T(n,"Subsys"),o=T(n,"ECode");for(let a of n.rows)t.push({at:he(n,a),type:"ERR",payload:{Subsys:i>=0?x(a[i]):null,ECode:o>=0?x(a[o]):null}})}let r=e.tables.MODE;if(r){let i=T(r,"TimeUS");for(let o of r.rows){let a={};r.columns.forEach((c,l)=>{if(l===i)return;a[c]=x(o[l])??H(o[l])}),t.push({at:he(r,o),type:"MODE",payload:a})}}let s=e.tables.MSG;if(s){let i=T(s,"Message")>=0?T(s,"Message"):T(s,"Msg");for(let o of s.rows)t.push({at:he(s,o),type:"MSG",payload:{text:i>=0?H(o[i]):null}})}return t}function Cr(e,t){let n=[],r=yr(t);if(r!==null)n.push({name:"vibe_peak",value:r,unit:"m/s/s"});let s=e.tables.ERR;if(s){let o=T(s,"Subsys"),a=T(s,"ECode");if(o>=0&&a>=0){let c=0;for(let l of s.rows)if(x(l[o])===6&&x(l[a])===1)c++;n.push({name:"failsafe_count",value:c})}}let i=br(t);if(i!==null)n.push({name:"hover_thr",value:i});return n}function ht(e,t,n){return{entity:Er(e),episode:kr(e,t,n.sourceHash),params:Tr(e),events:Sr(e),measurements:Cr(e,t)}}var _r,wr;var pt=M(()=>{_r={0:"Undefined",1:"Quad",2:"Hexa",3:"Octa",4:"OctaQuad",5:"Y6",6:"Heli",7:"Tri",8:"SingleCopter",9:"CoaxCopter",10:"BiCopter",11:"Heli_Dual",12:"DodecaHexa",13:"HeliQuad",14:"Deca",15:"Scripting"};wr=/^([A-Za-z][A-Za-z0-9_+\-]*)\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\b/});import{mkdir as Rr,readFile as be,writeFile as yt,readdir as bt,stat as Mr}from"fs/promises";import{dirname as Us,join as V}from"path";function _t(e,t,n){return V(e,".hydron","observations",t,K(n))}function K(e){return e.replace(/[^A-Za-z0-9._-]/g,"_")||"unknown"}function Ir(e,t){return typeof t==="bigint"?t.toString():t}function wt(e){if(Array.isArray(e.events))e.events=e.events.map((t)=>{let n=t.at,r;if(typeof n==="bigint")r=n;else if(typeof n==="string"&&/^-?\d+$/.test(n))r=BigInt(n);else if(typeof n==="number")r=BigInt(Math.trunc(n));else r=0n;return{...t,at:r}});return e}function Fr(e){let t=e.findings??[],n=t.filter((o)=>o.verdict==="FAIL").length,r=t.filter((o)=>o.severity==="CRITICAL"&&o.verdict==="FAIL").length,s="OK";for(let o of t)if(gt[o.severity]>gt[s])s=o.severity;let i=(o)=>e.measurements?.find((a)=>a.name===o)?.value??null;return{source_hash:e.episode.source_hash,logged_at:e.episode.logged_at,ruleset_version:e.ruleset_version,anomalies:n,critical:r,vibe_peak:i("vibe_peak"),failsafe_count:i("failsafe_count"),worst_severity:s,...e.tags&&e.tags.length>0?{tags:e.tags}:{}}}async function Pr(e){let t;try{t=await be(e,"utf8")}catch{return[]}let n=[];for(let r of t.split(`
|
|
5
5
|
`)){let s=r.trim();if(!s)continue;try{n.push(JSON.parse(s))}catch{}}return n}async function Dr(e,t){let n=V(e,"index.jsonl"),r=await Pr(n),s=Fr(t),i=r.filter((o)=>o.source_hash!==s.source_hash);i.push(s),await yt(n,i.map((o)=>JSON.stringify(o)).join(`
|
|
6
6
|
`)+`
|
|
7
7
|
`,"utf8")}async function vt(e,t){let n=_t(t.projectDir,t.workspace,e.entity.external_id);await Rr(n,{recursive:!0});let r=V(n,`${K(e.episode.source_hash)}.json`);return await yt(r,JSON.stringify(e,Ir,2),"utf8"),await Dr(n,e),r}async function Et(e){let t=_t(e.projectDir,e.workspace,e.sysid),n;try{n=await bt(t)}catch{return null}let r=`${K(e.excludeSourceHash)}.json`,s=n.filter((o)=>o.endsWith(".json")&&o!==r),i=null;for(let o of s){let a=V(t,o),c;try{let p=await be(a,"utf8");c=wt(JSON.parse(p))}catch{continue}let l=0;try{l=(await Mr(a)).mtimeMs}catch{}let u=c.episode?.logged_at?Date.parse(c.episode.logged_at):NaN,f=Number.isNaN(u)?-1/0:u;if(i===null||f>i.loggedAt||f===i.loggedAt&&l>i.mtime)i={doc:c,loggedAt:f,mtime:l}}return i?.doc??null}async function $r(e,t,n){let r=V(e,".hydron","observations",t),s=`${K(n)}.json`,i;try{i=await bt(r)}catch{return null}for(let o of i){let a=V(r,o,s),c;try{let l=await be(a,"utf8");c=wt(JSON.parse(l))}catch{continue}return{path:a,doc:c}}return null}async function At(e){let t=await $r(e.projectDir,e.workspace,e.flight_id);if(!t)return[];return(t.doc.findings??[]).filter((n)=>n.origin==="agent")}var gt;var kt=M(()=>{gt={OK:0,HIGH:1,CRITICAL:2}});function Or(e,t){let n=new Map;for(let s of e)n.set(s.name,s.value);let r=[];for(let s of t){let i=n.get(s.name);if(i===void 0)continue;if(i!==s.value)r.push({name:s.name,old:i,new:s.value})}return r}function xr(e,t){return Or(e.params??[],t.params??[])}function Lr(e,t){let n=new Map;for(let s of e.findings??[])if(s.tier==="system")n.set(s.check,s);let r=[];for(let s of t.findings??[]){if(s.tier!=="system")continue;let i=n.get(s.check);if(!i)continue;if(i.severity!==s.severity)r.push({check:s.check,old:i.severity,new:s.severity})}return r}function Tt(e,t){return{param_changes:xr(e,t),finding_changes:Lr(e,t)}}import{createHash as Nr}from"crypto";import{open as Ct,stat as Hr}from"fs/promises";import{resolve as Vr}from"path";async function Br(e){let t=await Ct(e,"r");try{let n=Buffer.alloc(2);return await t.read(n,0,2,0),n[0]===St[0]&&n[1]===St[1]}finally{await t.close()}}async function jr(e){let t=await Ct(e,"r");try{let n=Nr("sha256"),r=Buffer.alloc(1048576),s=0;for(;;){let{bytesRead:i}=await t.read(r,0,r.length,s);if(i===0)break;n.update(r.subarray(0,i)),s+=i}return n.digest("hex").slice(0,16)}finally{await t.close()}}function Ur(e){let t=e.filter((s)=>s.verdict==="FAIL").length,n=e.filter((s)=>s.severity==="CRITICAL"&&s.verdict==="FAIL").length,r=e.filter((s)=>s.verdict==="PASS").length;return{total:e.length,passed:r,anomalies:t,critical:n}}async function Rt(e,t){if(await Hr(e),!await Br(e))throw Error(`Not an ArduPilot DataFlash .bin (missing 0xA3 0x95 header): ${e}`);let n=await jr(e),r=lt(t.configDir??t.projectDir),{log:s,db:i,cleanup:o}=await j(e,n,{configDir:t.configDir??t.projectDir});try{let a=ht(s,i,{sourceHash:n});a.episode.attrs.source_path=Vr(e);let c=Je(s);a.episode.attrs.vehicle_type=c;let l=Qe(i,r,{vehicleType:c});l=[...l,...ot(a.params,{configDir:t.configDir??t.projectDir,ruleset_version:r.ruleset_version})];let u=await At({projectDir:t.projectDir,workspace:t.workspace,flight_id:n});l=[...l,...u];let f={schema_version:1,entity:a.entity,episode:a.episode,params:a.params,findings:l,events:a.events,measurements:a.measurements,ruleset_version:r.ruleset_version},p=await Et({projectDir:t.projectDir,workspace:t.workspace,sysid:a.entity.external_id,excludeSourceHash:n}),g=await vt(f,{projectDir:t.projectDir,workspace:t.workspace}),k={flight_id:n,vehicle_id:a.entity.external_id,metadata:{airframe:a.entity.attrs.name??a.entity.external_id,firmware:a.episode.attrs.firmware??null,duration_s:a.episode.attrs.duration_s??null},partial_decode:s.partial,decoded_until:s.decodedUntil,checks:l,summary:Ur(l),ruleset_version:r.ruleset_version};if(p){let{param_changes:S,finding_changes:y}=Tt(p,f);k.comparison={prior_flight_id:p.episode.source_hash,param_changes:S,finding_changes:y,narration:{claims:[]}}}return{report:k,doc:f,episodePath:g}}finally{o()}}var St;var Mt=M(()=>{ae();Ze();at();mt();pt();kt();St=[163,149]});import{readdir as Gr,readFile as Xr}from"fs/promises";import{join as It}from"path";async function qr(e,t,n){let r=It(e,".hydron","observations",t),s;try{s=await Gr(r)}catch{throw Error(`No observation store at ${r}. Run uav_analyze first.`)}for(let i of s){let o=It(r,i,`${n}.json`);try{let c=JSON.parse(await Xr(o,"utf8"))?.episode?.attrs?.source_path;if(typeof c==="string"&&c)return c;throw Error(`Episode ${n} has no source_path; re-run uav_analyze to record it.`)}catch(a){if(a.code==="ENOENT")continue;throw a}}throw Error(`flight_id ${n} not found in the observation store. Run uav_analyze first.`)}function Wr(e){let t=e.trim();t=t.replace(/^```(?:sql)?\s*/i,"").replace(/\s*```$/,"").trim();for(;;){let s=t;if(t=t.replace(/^--[^\n]*\n?/,"").replace(/^\/\*[\s\S]*?\*\//,"").trimStart(),t===s)break}if(t=t.replace(/;\s*$/,""),t.includes(";"))throw Error("Only a single statement is allowed (no ';').");let n=t.replace(/^\(+\s*/,"");if(!(/^\s*(select|with|values)\b/i.test(n)||/^\s*explain\b/i.test(t)||/^\s*pragma\s+(table_info|table_list|table_xinfo|index_list|index_info|index_xinfo|database_list|collation_list|function_list|pragma_list)\b/i.test(t)))throw Error("uav_query is read-only: use SELECT/WITH/VALUES (comments & ```fences ok), EXPLAIN, or a read PRAGMA (table_info/table_list/index_*). For heavier analysis use Python via bash, not SQL.");if(/\b(insert|update|delete|drop|create|alter|attach|detach|replace|reindex|vacuum)\b/i.test(t))throw Error("Write/DDL keyword detected \u2014 uav_query is read-only.");if(!/\blimit\b/i.test(t))t+=` LIMIT ${_e}`;return t}async function Ft(e){let t=Wr(e.query),n=await qr(e.projectDir,e.workspace,e.flight_id),{db:r,cleanup:s}=await j(n,e.flight_id);try{r.exec?.("PRAGMA query_only = ON");let o=r.query(t).all(),a=o.length?Object.keys(o[0]):[],l=o.slice(0,_e).map((u)=>a.map((f)=>u[f]));return{columns:a,rows:l,truncated:o.length>_e}}finally{s()}}var _e=1e4;var Pt=M(()=>{ae()});self.onmessage=async(e)=>{let t=e.data;try{let n;if(t.op==="analyze"){await Promise.resolve().then(() => Mt());n=await Rt(t.binPath,t.opts)}else if(t.op==="query"){await Promise.resolve().then(() => Pt());n=await Ft(t.opts)}else throw Error("unknown worker op");self.postMessage({ok:!0,result:n})}catch(n){self.postMessage({ok:!1,error:n instanceof Error?n.message:String(n)})}};
|