@h2loop/uav 1.2.0 → 1.2.2

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.
@@ -1,11 +1,7 @@
1
1
  // @bun
2
- var m$=Object.defineProperty;var p$=(Z)=>Z;function d$(Z,$){this[Z]=p$.bind(null,$)}var DZ=(Z,$)=>{for(var J in $)m$(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:d$.bind($,J)})};var M=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);function EZ(){let Z=process.env.UAV_DECODE_MAX_CPU;if(!Z)return;let $=Number(Z);return Number.isFinite($)&&$>0&&$<1?$:void 0}async function RZ(Z,$){if(!$||Z<=0)return;let J=Math.min(Z*(1/$-1),250);if(J>=1)await l$(J)}var l$=(Z)=>new Promise(($)=>setTimeout($,Z));var PZ;var TZ=M(()=>{PZ={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 n$}from"fs/promises";function o$(Z){return($,J)=>{let X="",Q=J+Z;for(let z=J;z<Q;z++){let K=$.getUint8(z);if(K===0)break;X+=String.fromCharCode(K)}return X}}function s$(Z){let $=Z.scale;switch(Z.kind){case"i8":return $===void 0?(J,X)=>J.getInt8(X):(J,X)=>J.getInt8(X)*$;case"u8":return $===void 0?(J,X)=>J.getUint8(X):(J,X)=>J.getUint8(X)*$;case"i16":return $===void 0?(J,X)=>J.getInt16(X,!0):(J,X)=>J.getInt16(X,!0)*$;case"u16":return $===void 0?(J,X)=>J.getUint16(X,!0):(J,X)=>J.getUint16(X,!0)*$;case"i32":return $===void 0?(J,X)=>J.getInt32(X,!0):(J,X)=>J.getInt32(X,!0)*$;case"u32":return $===void 0?(J,X)=>J.getUint32(X,!0):(J,X)=>J.getUint32(X,!0)*$;case"f32":return(J,X)=>J.getFloat32(X,!0);case"f64":return(J,X)=>J.getFloat64(X,!0);case"i64":return(J,X)=>J.getBigInt64(X,!0);case"u64":return(J,X)=>J.getBigUint64(X,!0);case"str":return o$(Z.width)}}function a$(Z,$){let J=[],X=[];for(let z of Z){let K=PZ[z];if(!K)return{readers:[],widths:[],ok:!1,timeIdx:-1};J.push(s$(K)),X.push(K.width)}let Q=$.indexOf("TimeUS");return{readers:J,widths:X,ok:!0,timeIdx:Q}}async function IZ(Z,$,J){let X=J??EZ(),Q=new Map,z={},K=!1,W=null,Y=null,G=4194304,B=await n$(Z,"r");try{let U=Buffer.allocUnsafe(G),O=new Uint8Array(0),N=0,P=!1;while(!P){let{bytesRead:_}=await B.read(U,0,G,N);N+=_,P=_===0;let j;if(_===0)j=O;else if(O.length===0)j=U.subarray(0,_);else j=new Uint8Array(O.length+_),j.set(O,0),j.set(U.subarray(0,_),O.length);let L=new DataView(j.buffer,j.byteOffset,j.byteLength),V=j.length,D=P,q=performance.now(),F=0;while(F+3<=V){if(j[F]!==i$||j[F+1]!==c$){F+=1;continue}let E=j[F+2],w=F+3;if(E===r$){if(w+_Z>V){if(D)K=!0;break}let v=j[w],FZ=j[w+1],p=e(j,w+2,4),h$=e(j,w+6,16),t=e(j,w+22,64).split(",").filter((x$)=>x$.length>0),{readers:b$,widths:g$,ok:f$,timeIdx:u$}=a$(h$,t);Q.set(v,{name:p,length:FZ,columns:t,ok:f$,payloadLen:FZ-3,readers:b$,widths:g$,timeIdx:u$}),$.onFmt(p,t),z[p]=(z[p]??0)+1,F+=3+_Z;continue}let S=Q.get(E);if(S===void 0){F+=1;continue}let y=S.payloadLen;if(w+y>V){if(D)K=!0;break}if(z[S.name]=(z[S.name]??0)+1,!S.ok){F+=3+y;continue}let{readers:s,widths:v$}=S,a=Array(s.length),AZ=w;for(let v=0;v<s.length;v++)a[v]=s[v](L,AZ),AZ+=v$[v];if($.onRow(S.name,a),S.timeIdx>=0){let v=a[S.timeIdx];if(typeof v==="bigint")Y=v}F+=3+y}if(O=j.slice(F),await RZ(performance.now()-q,X),P)break}}finally{await B.close()}if(K)W=Y;return{partial:K,decodedUntil:W,messageCounts:z}}function SZ(Z,$,J){let X=Z[$];if(!X)Z[$]={columns:J,rows:[]};else X.columns=J}async function MZ(Z){let $={},J=await IZ(Z,{onFmt:(X,Q)=>SZ($,X,Q),onRow:(X,Q)=>{$[X].rows.push(Q)}});return{partial:J.partial,decodedUntil:J.decodedUntil,tables:$,messageCounts:J.messageCounts}}async function CZ(Z,$,J={}){let X=J.retain??new Set,Q=5000,z={},K=new Map,W=await IZ(Z,{onFmt:(Y,G)=>{if(SZ(z,Y,G),$.table(Y,G),!K.has(Y))K.set(Y,[])},onRow:(Y,G)=>{let B=K.get(Y);if(B){if(B.push(G),B.length>=5000)$.rows(Y,B),B.length=0}if(X.has(Y))z[Y].rows.push(G)}});for(let[Y,G]of K)if(G.length)$.rows(Y,G);return{partial:W.partial,decodedUntil:W.decodedUntil,tables:z,messageCounts:W.messageCounts}}function e(Z,$,J){let X="",Q=$+J;for(let z=$;z<Q;z++){let K=Z[z];if(K===0)break;X+=String.fromCharCode(K)}return X}var i$=163,c$=149,r$=128,_Z=86;var wZ=M(()=>{TZ()});function e$(){let Z=process.env.UAV_PYTHON?.trim();if(Z)return[[Z]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function Z0(Z){try{return await Bun.spawn([...Z,"-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 $0(){if(yZ)return ZZ;for(let Z of e$())if(await Z0(Z)){ZZ=Z;break}return yZ=!0,ZZ}async function d(){let Z=await $0();if(!Z)throw Error(t$);return Z}var t$,ZZ=null,yZ=!1;var $Z=M(()=>{t$="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 J0}from"url";function kZ(Z){return typeof Z==="object"&&Z!==null&&"_summary"in Z}function z0(Z){if(typeof Z==="bigint")return Z;if(typeof Z==="number"&&Number.isFinite(Z))return BigInt(Math.trunc(Z));if(typeof Z==="string"&&/^-?\d+$/.test(Z))return BigInt(Z);return 0n}async function JZ(Z){let $=await d();if(await Bun.spawn([...$,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore"}).exited!==0)throw Error(`pymavlink not found \u2014 ${$.join(" ")} -m pip install pymavlink`);let X=Bun.spawn([...$,X0,Z],{stdout:"pipe",stderr:"pipe"}),Q=new Map,z={},K=!1,W=null,Y=null,G=!1;function B(L){let V=Q.get(L);if(!V)V={columns:[],colIndex:new Map,rows:[]},Q.set(L,V);return V}function U(L){let V=L.t,D=B(V),q=L.f;for(let E of Object.keys(q))if(!D.colIndex.has(E))D.colIndex.set(E,D.columns.length),D.columns.push(E);let F=Array(D.columns.length).fill(null);for(let E of Object.keys(q)){let w=D.colIndex.get(E),S=q[E],y=Q0.has(E)?z0(S):S;if(F[w]=y,E==="TimeUS"&&typeof y==="bigint")Y=y}D.rows.push(F)}let O=new TextDecoder,N="";for await(let L of X.stdout){N+=O.decode(L,{stream:!0});let V;while((V=N.indexOf(`
3
- `))!==-1){let D=N.slice(0,V);if(N=N.slice(V+1),D.length===0)continue;let q;try{q=JSON.parse(D)}catch{K=!0;continue}if(kZ(q)){G=!0;for(let[F,E]of Object.entries(q._summary.counts))z[F]=E;if(q._summary.partial)K=!0}else U(q)}}N+=O.decode();let P=N.trim();if(P.length>0)try{let L=JSON.parse(P);if(kZ(L)){G=!0;for(let[V,D]of Object.entries(L._summary.counts))z[V]=D;if(L._summary.partial)K=!0}else U(L)}catch{K=!0}let _=await X.exited;if(_!==0){if(!G){let L=(await new Response(X.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${_})${L?`: ${L}`:""}`)}K=!0}if(!G)K=!0;if(K)W=Y;let j={};for(let[L,V]of Q)j[L]={columns:V.columns,rows:V.rows};for(let[L,V]of Q)if(z[L]===void 0)z[L]=V.rows.length;return{partial:K,decodedUntil:W,tables:j,messageCounts:z}}var X0,Q0;var vZ=M(()=>{$Z();X0=J0(new URL("./mavdump.py",import.meta.url)),Q0=new Set(["TimeUS","TimeMS"])});import{fileURLToPath as K0}from"url";function G0(Z){return typeof Z==="object"&&Z!==null&&"_summary"in Z}function B0(Z){if(typeof Z==="bigint")return Z;if(typeof Z==="number"&&Number.isFinite(Z))return BigInt(Math.trunc(Z));if(typeof Z==="string"&&/^-?\d+$/.test(Z))return BigInt(Z);return 0n}async function H0(Z){let $=()=>Bun.spawn([...Z,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore"}).exited;if(await $()===0)return;if(await Bun.spawn([...Z,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore"}).exited,await $()!==0)throw Error(`pyulog not found \u2014 ${Z.join(" ")} -m pip install pyulog`)}async function hZ(Z){let $=await d();await H0($);let J=Bun.spawn([...$,W0,Z],{stdout:"pipe",stderr:"pipe"}),X=new Map,Q={},z=!1,K=null,W=null,Y=!1;function G(L){let V=X.get(L);if(!V)V={columns:[],colIndex:new Map,rows:[]},X.set(L,V);return V}function B(L){let V=L.t,D=G(V),q=L.f;for(let E of Object.keys(q))if(!D.colIndex.has(E))D.colIndex.set(E,D.columns.length),D.columns.push(E);let F=Array(D.columns.length).fill(null);for(let E of Object.keys(q)){let w=D.colIndex.get(E),S=q[E],y=Y0.has(E)?B0(S):S;if(F[w]=y,E==="timestamp"&&typeof y==="bigint")W=y}D.rows.push(F)}function U(L){if(L.length===0)return;let V;try{V=JSON.parse(L)}catch{z=!0;return}if(G0(V)){Y=!0;for(let[D,q]of Object.entries(V._summary.counts))Q[D]=q;if(V._summary.partial)z=!0}else B(V)}let O=new TextDecoder,N="";for await(let L of J.stdout){N+=O.decode(L,{stream:!0});let V;while((V=N.indexOf(`
4
- `))!==-1)U(N.slice(0,V)),N=N.slice(V+1)}N+=O.decode();let P=N.trim();if(P.length>0)U(P);let _=await J.exited;if(_!==0){if(!Y){let L=(await new Response(J.stderr).text()).trim();throw Error(`ulog decode failed (exit ${_})${L?`: ${L}`:""}`)}z=!0}if(!Y)z=!0;if(z)K=W;let j={};for(let[L,V]of X)j[L]={columns:V.columns,rows:V.rows};for(let[L,V]of X)if(Q[L]===void 0)Q[L]=V.rows.length;return{partial:z,decodedUntil:K,tables:j,messageCounts:Q}}var W0,Y0;var bZ=M(()=>{$Z();W0=K0(new URL("./ulog.py",import.meta.url)),Y0=new Set(["timestamp","timestamp_sample"])});import{existsSync as gZ,readFileSync as U0}from"fs";import{mkdtemp as V0,rm as L0}from"fs/promises";import{tmpdir as O0}from"os";import{basename as XZ,join as QZ}from"path";function fZ(Z){if(!Z)return[];let $=QZ(Z,".hydron","uav-format-converters.json");if(!gZ($))return[];try{let J=JSON.parse(U0($,"utf8"));return Array.isArray(J.converters)?J.converters.filter((X)=>X&&X.match&&X.command):[]}catch{return[]}}function uZ(Z,$){for(let J of $)try{if(new RegExp(J.match,"i").test(Z))return J}catch{}return null}async function xZ(Z,$){let J=await V0(QZ(O0(),"uav-convert-")),X=XZ(Z).replace(/\.[^.]+$/,""),Q=QZ(J,X+($.produces??".bin")),z=$.command.replaceAll("{input}",Z).replaceAll("{output}",Q),K=()=>L0(J,{recursive:!0,force:!0});try{let W=process.platform==="win32"?["cmd.exe","/d","/s","/c",z]:["bash","-lc",z],Y=Bun.spawn(W,{stdout:"pipe",stderr:"pipe"}),G=await Y.exited;if(G!==0){let B=(await new Response(Y.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${G}) for ${XZ(Z)}: ${B}`)}if(!gZ(Q))throw Error(`format converter produced no output for ${XZ(Z)}`);return{out:Q,cleanup:K}}catch(W){throw await K(),W}}var mZ=()=>{};import{Database as N0}from"bun:sqlite";import{tmpdir as j0}from"os";import{join as q0}from"path";import{existsSync as pZ,unlinkSync as dZ}from"fs";function nZ(Z){let $=q0(j0(),`uav-${Z}-${process.pid}-${A0++}.sqlite`);try{if(pZ($))dZ($)}catch{}let J=new N0($);return J.exec("PRAGMA page_size = 8192"),J.query("PRAGMA journal_mode = MEMORY").get(),J.exec("PRAGMA synchronous = OFF"),J.exec("PRAGMA temp_store = FILE"),J.exec("PRAGMA cache_size = -65536"),{db:J,cleanup(){try{J.close()}catch{}try{if(pZ($))dZ($)}catch{}}}}function KZ(Z){let $=new Map,J=new Map;return{table(X,Q){if($.has(X)||Q.length===0)return;Z.run(`CREATE TABLE ${zZ(X)} (${Q.map(zZ).join(", ")})`);let z=Q.map(()=>"?").join(", ");$.set(X,Z.query(`INSERT INTO ${zZ(X)} VALUES (${z})`)),J.set(X,Q.length)},rows(X,Q){let z=$.get(X),K=J.get(X);if(!z||K===void 0||Q.length===0)return;let W=Z.transaction((Y)=>{for(let G of Y){let B=Array(K);for(let U=0;U<K;U++){let O=G[U];B[U]=O===void 0?null:O}z.run(...B)}});for(let Y=0;Y<Q.length;Y+=lZ)W(Q.slice(Y,Y+lZ))}}}function iZ(Z,$){let J=KZ(Z);for(let[X,Q]of Object.entries($.tables)){if(Q.columns.length===0)continue;if(J.table(X,Q.columns),Q.rows.length)J.rows(X,Q.rows)}}var A0=0,zZ=(Z)=>`"${Z.replace(/"/g,'""')}"`,lZ=5000;var cZ=()=>{};async function m(Z,$="flight",J){let X=uZ(Z,fZ(J?.configDir));if(X){let{out:K,cleanup:W}=await xZ(Z,X);try{return await m(K,$)}finally{await W()}}let{db:Q,cleanup:z}=nZ($);try{let K=Z.toLowerCase();if(K.endsWith(".bin"))return{log:await CZ(Z,KZ(Q),{retain:F0}),db:Q,cleanup:z};let W;if(K.endsWith(".ulog"))W=await hZ(Z);else if(K.endsWith(".tlog")||K.endsWith(".log"))W=await JZ(Z);else try{W=await MZ(Z)}catch{W=await JZ(Z)}return iZ(Q,W),{log:W,db:Q,cleanup:z}}catch(K){throw z(),K}}var F0;var WZ=M(()=>{wZ();vZ();bZ();mZ();cZ();F0=new Set(["PARM","MSG","GPS","ERR","MODE"])});function YZ(Z,$){let J=Z.tables.PARM;if(!J)return null;let X=J.columns.findIndex((K)=>K.toLowerCase()==="name"),Q=J.columns.findIndex((K)=>K.toLowerCase()==="value");if(X<0||Q<0)return null;let z=$.toLowerCase();for(let K of J.rows)if(String(K[X]).toLowerCase()===z){let W=Number(K[Q]);return Number.isFinite(W)?W:null}return null}function D0(Z){let $=Z.tables.MSG;if(!$)return"";let J=$.columns.findIndex((X)=>/message|msg/i.test(X));if(J<0)return"";for(let X of $.rows){let Q=String(X[J]??"");if(/Ardu(Copter|Plane|Sub|Rover)|PX4/i.test(Q))return Q}return""}function rZ(Z){let $=YZ(Z,"Q_ENABLE");if($!==null&&$>=1||Z.tables.QUIK||Z.tables.AETR){if(Z.tables.MOTB||YZ(Z,"FRAME_CLASS")!==null||Z.tables.ARSP)return"vtol"}if($!==null&&$>=1)return"vtol";let J=D0(Z);if(/ArduPlane/i.test(J))return"fixedwing";if(/ArduCopter/i.test(J))return"multirotor";if(YZ(Z,"FRAME_CLASS")!==null)return"multirotor";if(Z.tables.ARSP&&!Z.tables.MOTB)return"fixedwing";if(Z.tables.MOTB||Z.tables.RATE)return"multirotor";return"unknown"}function l(Z){return Z===void 0||Z==="multirotor"||Z==="vtol"||Z==="unknown"}function oZ(Z){return Z==="fixedwing"||Z==="vtol"}function C(Z){return`"${Z.replace(/"/g,'""')}"`}function A(Z,$){let J=Z.db.query($).get();if(!J)return null;let X=Object.values(J)[0];if(X===null||X===void 0)return null;return Number(X)}function k(Z,$){try{let J=Z.db.query(`PRAGMA table_info(${C($)})`).all();return new Set(J.map((X)=>X.name))}catch{return new Set}}function I(Z,$,J){return k(Z,$).has(J)}function aZ(Z,$){for(let J of $)if(Z.hasTable(J))return J;return null}function H(Z,$,J){return{check:Z,severity:"OK",value:null,threshold_used:null,ruleset_version:$.ruleset_version,verdict:"SKIP",tier:"system",...J?{detail:J}:{}}}function R(Z){return{check:Z.check,severity:Z.failed?Z.failSeverity:"OK",value:Z.value,threshold_used:Z.threshold_used,ruleset_version:Z.thresholds.ruleset_version,verdict:Z.failed?"FAIL":"PASS",tier:"system",...Z.source?{source:Z.source}:{},...Z.detail?{detail:Z.detail}:{}}}function M0(Z,$,J){let X=Object.values(Z);if($<=0||X.length===0)return"";let Q=[...X].sort((G,B)=>B-G),z=Q[0],K=Q.length>1?Q[1]:0;if(Q.length>=2&&K>0&&z>=2*K)return" | cause: likely sensor/mounting alignment (one axis dominates)";let Y=Q.length>=2&&z<=1.5*(Q[Q.length-1]||z);if(J>0||Y)return" | cause: likely mechanical degradation (props/bearings/frame)";return""}function tZ(Z,$,J){let X=new Set;try{let K=Z.query("SELECT name FROM sqlite_master WHERE type='table'").all();for(let W of K)X.add(W.name)}catch{}let Q={db:Z,thresholds:$,hasTable:(K)=>X.has(K),vehicleType:J?.vehicleType},z=[];for(let{id:K,run:W}of o0)try{z.push(W(Q))}catch(Y){let G=Y instanceof Error?Y.message:String(Y);z.push(H(K,$,`check error: ${G}`))}return z}var E0=(Z)=>{let $=Z.thresholds.battery;if(!Z.hasTable("ERR"))return H("battery",Z.thresholds);if(!I(Z,"ERR","Subsys")||!I(Z,"ERR","ECode"))return H("battery",Z.thresholds,"ERR present but Subsys/ECode columns absent");let J=$?.err_subsys??6,X=$?.err_ecode??1,Q=A(Z,`SELECT COUNT(*) FROM "ERR" WHERE "Subsys"=${J} AND "ECode"=${X}`)??0;return R({check:"battery",thresholds:Z.thresholds,failed:Q>0,failSeverity:"CRITICAL",value:Q,threshold_used:0,source:$?.source,detail:Q>0?`${Q} battery failsafe ERR event(s) (Subsys=${J} ECode=${X})`:void 0})},R0=(Z)=>{let $=Z.thresholds.attitude;if(!Z.hasTable("ATT"))return H("attitude",Z.thresholds);for(let K of["DesRoll","Roll","DesPitch","Pitch"])if(!I(Z,"ATT",K))return H("attitude",Z.thresholds,`ATT missing column ${K}`);let J=$?.max_deg??5,X=A(Z,'SELECT MAX(ABS("DesRoll"-"Roll")) FROM "ATT"'),Q=A(Z,'SELECT MAX(ABS("DesPitch"-"Pitch")) FROM "ATT"'),z=Math.max(X??0,Q??0);return R({check:"attitude",thresholds:Z.thresholds,failed:z>J,failSeverity:"HIGH",value:z,threshold_used:J,source:$?.source,detail:`peak roll err ${(X??0).toFixed(2)}\xB0, pitch err ${(Q??0).toFixed(2)}\xB0`})},P0=(Z)=>{let $=Z.thresholds.altitude;if(!Z.hasTable("CTUN"))return H("altitude",Z.thresholds);if(!I(Z,"CTUN","DAlt")||!I(Z,"CTUN","Alt"))return H("altitude",Z.thresholds,"CTUN missing DAlt/Alt columns");let J=$?.max_m??2,X=A(Z,'SELECT MAX(ABS("DAlt"-"Alt")) FROM "CTUN"');return R({check:"altitude",thresholds:Z.thresholds,failed:(X??0)>J,failSeverity:"HIGH",value:X,threshold_used:J,source:$?.source})},T0=(Z)=>{let $=Z.thresholds.hover;if(!l(Z.vehicleType))return H("hover",Z.thresholds,`n/a for ${Z.vehicleType} (no hover throttle)`);if(!Z.hasTable("CTUN"))return H("hover",Z.thresholds);if(!I(Z,"CTUN","ThH"))return H("hover",Z.thresholds,"CTUN missing ThH column");let J=$?.band??[0.25,0.75],[X,Q]=J,z=A(Z,'SELECT AVG("ThH") FROM "CTUN"'),K=z===null?!1:z<X||z>Q;return R({check:"hover",thresholds:Z.thresholds,failed:K,failSeverity:"HIGH",value:z,threshold_used:Q,source:$?.source,detail:`mean hover throttle ${(z??0).toFixed(3)} vs band [${X}, ${Q}]`})},sZ=2000,_0=(Z)=>{if(!l(Z.vehicleType))return H("rcou",Z.thresholds,`n/a for ${Z.vehicleType} (control surfaces, not motor mix)`);if(!Z.hasTable("RCOU"))return H("rcou",Z.thresholds);let $=k(Z,"RCOU"),J=[];for(let z=1;z<=8;z++)if($.has(`C${z}`))J.push(`C${z}`);if(J.length===0)return H("rcou",Z.thresholds,"RCOU has no C1..C8 channels");let X=-1/0,Q=[];for(let z of J){let K=A(Z,`SELECT MAX(${C(z)}) FROM "RCOU"`);if(K===null)continue;if(K>X)X=K;if(K>=sZ)Q.push(`${z}=${K}`)}if(X===-1/0)X=0;return R({check:"rcou",thresholds:Z.thresholds,failed:Q.length>0,failSeverity:"HIGH",value:X,threshold_used:sZ,detail:Q.length>0?`motor output(s) pegged at max: ${Q.join(", ")}`:void 0})},GZ=1000,BZ=2000,I0=(Z)=>{if(!Z.hasTable("RCIN"))return H("rcin",Z.thresholds);if(!I(Z,"RCIN","C3"))return H("rcin",Z.thresholds,"RCIN missing C3 column");let $=A(Z,'SELECT MIN("C3") FROM "RCIN"'),J=A(Z,'SELECT MAX("C3") FROM "RCIN"'),X=$!==null&&$<GZ||J!==null&&J>BZ,Q=J;if($!==null&&$<GZ)Q=$;return R({check:"rcin",thresholds:Z.thresholds,failed:X,failSeverity:"HIGH",value:Q,threshold_used:BZ,detail:`RCIN C3 range [${$??"\u2014"}, ${J??"\u2014"}] vs [${GZ}, ${BZ}]`})},S0=(Z)=>{let $=Z.thresholds.vibration;if(!Z.hasTable("VIBE"))return H("vibration",Z.thresholds);let J=k(Z,"VIBE"),X=["VibeX","VibeY","VibeZ"].filter((U)=>J.has(U));if(X.length===0)return H("vibration",Z.thresholds,"VIBE has no VibeX/Y/Z columns");let Q=$?.max_ms2??30,z={},K=-1/0;for(let U of X){let N=A(Z,`SELECT MAX(${C(U)}) FROM "VIBE"`)??0;if(z[U]=N,N>K)K=N}if(K===-1/0)K=0;let W=["Clip","Clip0","Clip1","Clip2"].filter((U)=>J.has(U)),Y=0;for(let U of W){let O=A(Z,`SELECT MAX(${C(U)}) FROM "VIBE"`);if(O!==null&&O>Y)Y=O}let G=W.length>0?` | clipping MAX=${Y}${Y>0?" (CLIP EVENTS)":""}`:"",B=M0(z,K,Y);return R({check:"vibration",thresholds:Z.thresholds,failed:K>=Q,failSeverity:"HIGH",value:K,threshold_used:Q,source:$?.source,detail:`peak vibe ${K} m/s\xB2 (axes ${X.join("/")})${G}${B}`})},C0=(Z)=>{let $=Z.thresholds.mag;if(!Z.hasTable("MAG"))return H("mag",Z.thresholds);if(!I(Z,"MAG","Health"))return H("mag",Z.thresholds,"MAG missing Health column");let J=$?.min??1,X=A(Z,'SELECT MIN("Health") FROM "MAG"');return R({check:"mag",thresholds:Z.thresholds,failed:X!==null&&X<J,failSeverity:"HIGH",value:X,threshold_used:J,source:$?.source})},w0=(Z)=>{let $=Z.thresholds.ekf,J=aZ(Z,["XKF3","NKF3"]);if(!J)return H("ekf",Z.thresholds);let X=k(Z,J),Q=["IVN","IVE","IVD","IVT","IPN","IPE","IPD"].filter((W)=>X.has(W));if(Q.length===0)return H("ekf",Z.thresholds,`${J} has no IVN/IVE/IVD/IVT/IPN/IPE/IPD columns`);let z=$?.max_ratio??0.5,K=-1/0;for(let W of Q){let Y=A(Z,`SELECT MAX(ABS(${C(W)})) FROM ${C(J)}`);if(Y!==null&&Y>K)K=Y}if(K===-1/0)K=0;return R({check:"ekf",thresholds:Z.thresholds,failed:K>z,failSeverity:"HIGH",value:K,threshold_used:z,source:$?.source,detail:`peak innovation ${K} (${J}: ${Q.join("/")})`})},y0=(Z)=>{let $=Z.thresholds.battery;if(!Z.hasTable("BAT"))return H("min_cell_voltage",Z.thresholds);if(!I(Z,"BAT","Volt"))return H("min_cell_voltage",Z.thresholds,"BAT missing Volt column");let J=$?.min_cell_v??3.3,X=A(Z,'SELECT MAX("Volt") FROM "BAT"'),Q=A(Z,'SELECT MIN("Volt") FROM "BAT"');if(X===null||Q===null||X<=0)return H("min_cell_voltage",Z.thresholds,"BAT.Volt has no usable values");let z=Math.max(1,Math.round(X/4.2)),K=Q/z;return R({check:"min_cell_voltage",thresholds:Z.thresholds,failed:K<J,failSeverity:"CRITICAL",value:K,threshold_used:J,source:$?.source,detail:`${z}S pack (MAX pack ${X.toFixed(2)}V), min cell ${K.toFixed(3)}V vs floor ${J}V`})},k0=(Z)=>{let $=Z.thresholds.battery;if(!Z.hasTable("BAT"))return H("voltage_sag",Z.thresholds);if(!I(Z,"BAT","VoltR")||!I(Z,"BAT","Volt"))return H("voltage_sag",Z.thresholds,"BAT missing VoltR/Volt columns");let J=$?.max_sag_v??2,X=A(Z,'SELECT MAX("VoltR"-"Volt") FROM "BAT"');return R({check:"voltage_sag",thresholds:Z.thresholds,failed:X!==null&&X>J,failSeverity:"HIGH",value:X,threshold_used:J,source:$?.source,detail:`peak sag ${(X??0).toFixed(2)}V (VoltR-Volt) vs ${J}V`})},v0=(Z)=>{let $=Z.thresholds.battery;if(!Z.hasTable("BAT"))return H("over_current",Z.thresholds);if(!I(Z,"BAT","Curr"))return H("over_current",Z.thresholds,"BAT missing Curr column");let J=$?.max_current_a??200,X=A(Z,'SELECT MAX("Curr") FROM "BAT"');return R({check:"over_current",thresholds:Z.thresholds,failed:X!==null&&X>J,failSeverity:"HIGH",value:X,threshold_used:J,source:$?.source,detail:`peak current ${(X??0).toFixed(1)}A vs ${J}A`})},h0=(Z)=>{let $=Z.thresholds.battery;if(!Z.hasTable("BAT"))return H("internal_resistance",Z.thresholds);if(!I(Z,"BAT","Res"))return H("internal_resistance",Z.thresholds,"BAT missing Res column");let J=A(Z,'SELECT MAX("Res") FROM "BAT"');if(J===null||J===0)return H("internal_resistance",Z.thresholds,"BAT.Res all zero/absent (not reported)");let X=$?.res_min_current_a??5,z=I(Z,"BAT","Curr")?A(Z,`SELECT MAX("Res") FROM "BAT" WHERE "Curr" >= ${X}`):J;if(z===null)return H("internal_resistance",Z.thresholds,`no BAT samples at Curr \u2265 ${X} A \u2014 Res only valid under load (max raw ${J.toFixed(3)}\u03A9 is a low-current artifact)`);let K=$?.max_res_ohm??0.03;return R({check:"internal_resistance",thresholds:Z.thresholds,failed:z>K,failSeverity:"HIGH",value:z,threshold_used:K,source:$?.source,detail:`peak internal resistance ${z.toFixed(4)}\u03A9 (at Curr \u2265 ${X} A) vs ${K}\u03A9`})},b0=(Z)=>{let $=Z.thresholds.power;if(!Z.hasTable("POWR"))return H("board_brownout",Z.thresholds);if(!I(Z,"POWR","Vcc"))return H("board_brownout",Z.thresholds,"POWR missing Vcc column");let J=$?.min_vcc_v??4.5,X=A(Z,'SELECT MIN("Vcc") FROM "POWR"');return R({check:"board_brownout",thresholds:Z.thresholds,failed:X!==null&&X<J,failSeverity:"CRITICAL",value:X,threshold_used:J,source:$?.source,detail:`min board Vcc ${(X??0).toFixed(3)}V vs floor ${J}V`})},g0=(Z)=>{let $=Z.thresholds.rate;if(!Z.hasTable("RATE"))return H("rate_tracking",Z.thresholds);let J=k(Z,"RATE"),Q=[["RDes","R"],["PDes","P"],["YDes","Y"]].filter(([Y,G])=>J.has(Y)&&J.has(G));if(Q.length===0)return H("rate_tracking",Z.thresholds,"RATE has no RDes/R, PDes/P, YDes/Y pairs");let z=$?.max_err_dps??50,K=-1/0,W="";for(let[Y,G]of Q){let B=A(Z,`SELECT MAX(ABS(${C(Y)}-${C(G)})) FROM "RATE"`);if(B!==null&&B>K)K=B,W=Y.replace("Des","")}if(K===-1/0)K=0;return R({check:"rate_tracking",thresholds:Z.thresholds,failed:K>z,failSeverity:"HIGH",value:K,threshold_used:z,source:$?.source,detail:`peak rate-tracking error ${K.toFixed(2)} deg/s (axis ${W||"?"}) vs ${z} deg/s`})},f0=(Z)=>{let $=Z.thresholds.gps;if(!Z.hasTable("GPA"))return H("gps_accuracy",Z.thresholds);if(!I(Z,"GPA","HAcc"))return H("gps_accuracy",Z.thresholds,"GPA missing HAcc column");let J=$?.hacc_max_m??5,X=A(Z,'SELECT MAX("HAcc") FROM "GPA"');return R({check:"gps_accuracy",thresholds:Z.thresholds,failed:X!==null&&X>J,failSeverity:"HIGH",value:X,threshold_used:J,source:$?.source,detail:`peak horizontal accuracy ${(X??0).toFixed(2)}m vs ${J}m`})},u0=(Z)=>{let $=Z.thresholds.ekf,J=aZ(Z,["XKF4","NKF4"]);if(!J)return H("ekf_variance",Z.thresholds);let X=k(Z,J),Q=["SV","SP","SH","SM"].filter((B)=>X.has(B));if(Q.length===0)return H("ekf_variance",Z.thresholds,`${J} has no SV/SP/SH/SM columns`);let z=$?.max_variance??1,K=-1/0,W="";for(let B of Q){let U=A(Z,`SELECT MAX(${C(B)}) FROM ${C(J)}`);if(U!==null&&U>K)K=U,W=B}if(K===-1/0)K=0;let Y=X.has("FS")?A(Z,`SELECT MAX("FS") FROM ${C(J)}`):null,G=Y!==null&&Y>0?` | EKF failsafe set (FS MAX=${Y})`:"";return R({check:"ekf_variance",thresholds:Z.thresholds,failed:K>z,failSeverity:"HIGH",value:K,threshold_used:z,source:$?.source,detail:`peak EKF variance ${K.toFixed(3)} (${J}: ${W||Q.join("/")}) vs ${z}${G}`})},x0=(Z)=>{let $=Z.thresholds.mag;if(!Z.hasTable("MAG"))return H("mag_offsets",Z.thresholds);let J=k(Z,"MAG"),X=["OfsX","OfsY","OfsZ"].filter((W)=>J.has(W));if(X.length===0)return H("mag_offsets",Z.thresholds,"MAG has no OfsX/OfsY/OfsZ columns");let Q=$?.max_offset??600,z=-1/0,K="";for(let W of X){let Y=A(Z,`SELECT MAX(ABS(${C(W)})) FROM "MAG"`);if(Y!==null&&Y>z)z=Y,K=W}if(z===-1/0)z=0;return R({check:"mag_offsets",thresholds:Z.thresholds,failed:z>Q,failSeverity:"HIGH",value:z,threshold_used:Q,source:$?.source,detail:`peak mag offset ${z.toFixed(0)} (${K||X.join("/")}) vs ${Q}`})},m0=(Z)=>{let $=Z.thresholds.esc;if(!Z.hasTable("ESC"))return H("esc_health",Z.thresholds);let J=k(Z,"ESC"),X=["Temp","MotTemp"].filter((U)=>J.has(U));if(X.length===0&&!J.has("Err"))return H("esc_health",Z.thresholds,"ESC has no Temp/MotTemp/Err columns");let Q=$?.max_temp_c??90,z=-1/0,K="";for(let U of X){let O=A(Z,`SELECT MAX(${C(U)}) FROM "ESC"`);if(O!==null&&O>z)z=O,K=U}if(z===-1/0)z=0;let W=J.has("Err")?A(Z,'SELECT MAX("Err") FROM "ESC"')??0:0,Y=X.length>0&&z>Q,G=W>0,B=G?` | ESC Err MAX=${W}`:"";return R({check:"esc_health",thresholds:Z.thresholds,failed:Y||G,failSeverity:"HIGH",value:z,threshold_used:Q,source:$?.source,detail:`peak ESC temp ${z.toFixed(1)}\xB0C (${K||"n/a"}) vs ${Q}\xB0C${B}`})},p0=(Z)=>{if(!l(Z.vehicleType))return H("thrust_margin",Z.thresholds,`n/a for ${Z.vehicleType} (lift/T:W is a rotorcraft metric)`);if(!Z.hasTable("MOTB"))return H("thrust_margin",Z.thresholds);let $=k(Z,"MOTB");if(!$.has("FailFlags")&&!($.has("ThrOut")&&$.has("LiftMax")))return H("thrust_margin",Z.thresholds,"MOTB missing FailFlags and ThrOut/LiftMax columns");let J=$.has("FailFlags")?A(Z,'SELECT MAX("FailFlags") FROM "MOTB"')??0:0,X=null;if($.has("ThrOut")&&$.has("LiftMax")){let W=A(Z,'SELECT AVG("ThrOut") FROM "MOTB"'),Y=A(Z,'SELECT AVG("LiftMax") FROM "MOTB"');if(W!==null&&Y!==null&&Y>0)X=W/Y}let Q=X!==null&&X>0.5,z=J>0,K=`MOTB FailFlags MAX=${J}`+(X!==null?`, mean ThrOut/LiftMax ${X.toFixed(2)} (low-margin > 0.5)`:"")+(z?" \u2014 THRUST-LOSS flagged":Q?" \u2014 low thrust margin":"");return R({check:"thrust_margin",thresholds:Z.thresholds,failed:z||Q,failSeverity:"HIGH",value:X,threshold_used:0.5,detail:K})},d0=(Z)=>{let $=Z.thresholds.imu;if(!Z.hasTable("IMU"))return H("imu_health",Z.thresholds);let J=k(Z,"IMU"),X=["EG","EA"].filter((W)=>J.has(W));if(X.length===0)return H("imu_health",Z.thresholds,"IMU has no EG/EA error-count columns");let Q=$?.max_err??0,z=-1/0,K="";for(let W of X){let Y=A(Z,`SELECT MAX(${C(W)}) FROM "IMU"`);if(Y!==null&&Y>z)z=Y,K=W}if(z===-1/0)z=0;return R({check:"imu_health",thresholds:Z.thresholds,failed:z>Q,failSeverity:"HIGH",value:z,threshold_used:Q,source:$?.source,detail:`max IMU error count ${z} (${K||X.join("/")}) vs ${Q}`})},l0=(Z)=>{let $=Z.thresholds.imu;if(!Z.hasTable("IMU"))return H("imu_consistency",Z.thresholds);let J=k(Z,"IMU");if(!J.has("I"))return H("imu_consistency",Z.thresholds,"IMU has no instance column I");let X=["AccX","AccY","AccZ"].filter((q)=>J.has(q)),Q=["GyrX","GyrY","GyrZ"].filter((q)=>J.has(q));if(X.length===0&&Q.length===0)return H("imu_consistency",Z.thresholds,"IMU has no Acc*/Gyr* columns");let z=[...X,...Q].map((q)=>`AVG(${C(q)}) ${C(q)}`).join(", "),K=Z.db.query(`SELECT "I" AS "I", ${z} FROM "IMU" GROUP BY "I"`).all();if(K.length<2)return H("imu_consistency",Z.thresholds,`only ${K.length} IMU instance \u2014 nothing to cross-check`);let W=(q)=>{let F=K.map((E)=>Number(E[q])).filter((E)=>Number.isFinite(E));return F.length>=2?Math.max(...F)-Math.min(...F):0},Y=0,G="";for(let q of X){let F=W(q);if(F>Y)Y=F,G=q}let B=0,U="";for(let q of Q){let F=W(q);if(F>B)B=F,U=q}let O=$?.accel_consistency_max??0.7,N=$?.gyro_consistency_max??0.3,P=Y>O,_=B>N,j=P||_,L=Y/O>=B/N?Y:B,V=Y/O>=B/N?O:N,D=j?`INCONSISTENT \u2014 ${P?`accel ${G} spread ${Y.toFixed(3)} m/s\xB2 > ${O}`:""}${P&&_?"; ":""}${_?`gyro ${U} spread ${B.toFixed(3)} rad/s > ${N}`:""}`:`IMUs consistent \u2014 max inter-instance bias spread: accel ${Y.toFixed(3)} m/s\xB2 (<${O}), gyro ${B.toFixed(3)} rad/s (<${N}); relative differences between instances are within healthy tolerance`;return R({check:"imu_consistency",thresholds:Z.thresholds,failed:j,failSeverity:"HIGH",value:L,threshold_used:V,source:{kind:"rule-of-thumb",ref:"IMU inconsistency tolerance (~ArduPilot arming limits)"},detail:D})},n0=(Z)=>{if(!Z.hasTable("ERR"))return H("err_events",Z.thresholds);if(!I(Z,"ERR","Subsys")||!I(Z,"ERR","ECode"))return H("err_events",Z.thresholds,"ERR present but Subsys/ECode columns absent");let $=Z.thresholds.battery?.err_subsys??6,J=Z.db.query(`SELECT "Subsys" AS subsys, "ECode" AS ecode, COUNT(*) AS n FROM "ERR" WHERE "ECode" <> 0 AND "Subsys" <> ${$} GROUP BY "Subsys", "ECode" ORDER BY "Subsys", "ECode"`).all(),X=0,Q=[];for(let z of J)X+=Number(z.n),Q.push(`Subsys=${z.subsys} ECode=${z.ecode} \xD7${z.n}`);return R({check:"err_events",thresholds:Z.thresholds,failed:X>0,failSeverity:"HIGH",value:X,threshold_used:0,detail:X>0?`${X} non-battery ERR event(s): ${Q.join(", ")}`:"no non-battery ERR events"})},i0,c0=(Z)=>{if(!Z.hasTable("MODE"))return H("mode_changes",Z.thresholds);if(!I(Z,"MODE","ModeNum"))return H("mode_changes",Z.thresholds,"MODE missing ModeNum column");let $=Z.db.query('SELECT "ModeNum" AS modenum FROM "MODE"').all(),J=$.length,X=J>0?J-1:0,Q=new Map,z=!1;for(let W of $){let Y=Number(W.modenum);if(Q.set(Y,(Q.get(Y)??0)+1),i0.has(Y))z=!0}let K=[...Q.entries()].sort((W,Y)=>W[0]-Y[0]).map(([W,Y])=>`Mode${W}\xD7${Y}`).join(", ");return R({check:"mode_changes",thresholds:Z.thresholds,failed:z,failSeverity:"HIGH",value:X,threshold_used:0,detail:`${X} mode change(s); timeline: ${K||"\u2014"}`+(z?" \u2014 emergency mode (RTL/LAND) entered":"")})},r0=(Z)=>{let $=Z.thresholds.airspeed;if(!oZ(Z.vehicleType))return H("airspeed",Z.thresholds,`n/a for ${Z.vehicleType} (no fixed-wing airspeed)`);if(!Z.hasTable("ARSP"))return H("airspeed",Z.thresholds,"no ARSP (airspeed) data");if(!I(Z,"ARSP","Airspeed"))return H("airspeed",Z.thresholds,"ARSP missing Airspeed column");let J=$?.stall_min_ms??8,X={kind:"rule-of-thumb",ref:"default stall floor"};if(Z.hasTable("PARM")){let z=A(Z,`SELECT "Value" FROM "PARM" WHERE "Name"='ARSPD_FBW_MIN' LIMIT 1`);if(z!==null&&z>0)J=z,X={kind:"datasheet",ref:"ARSPD_FBW_MIN"}}let Q=A(Z,'SELECT MIN("Airspeed") FROM "ARSP" WHERE "Airspeed" > 2');if(Q===null)return H("airspeed",Z.thresholds,"no airborne airspeed samples");return R({check:"airspeed",thresholds:Z.thresholds,failed:Q<J,failSeverity:"HIGH",value:Q,threshold_used:J,source:X,detail:`min in-flight airspeed ${Q.toFixed(1)} m/s vs stall floor ${J} m/s`})},o0;var eZ=M(()=>{i0=new Set([6,9]),o0=[{id:"battery",run:E0},{id:"min_cell_voltage",run:y0},{id:"voltage_sag",run:k0},{id:"over_current",run:v0},{id:"internal_resistance",run:h0},{id:"board_brownout",run:b0},{id:"attitude",run:R0},{id:"rate_tracking",run:g0},{id:"altitude",run:P0},{id:"hover",run:T0},{id:"rcou",run:_0},{id:"rcin",run:I0},{id:"thrust_margin",run:p0},{id:"vibration",run:S0},{id:"imu_health",run:d0},{id:"imu_consistency",run:l0},{id:"mag",run:C0},{id:"mag_offsets",run:x0},{id:"gps_accuracy",run:f0},{id:"ekf",run:w0},{id:"ekf_variance",run:u0},{id:"esc_health",run:m0},{id:"airspeed",run:r0},{id:"err_events",run:n0},{id:"mode_changes",run:c0}]});import{existsSync as s0,readFileSync as a0}from"fs";import{dirname as t0,join as HZ}from"path";import{fileURLToPath as e0}from"url";function J$(Z){if(Z){let $=HZ(Z,".hydron","apm-params.json"),J=$$($);if(J&&J.size>0)return J}for(let $ of Z8){let J=$$($);if(J)return J}return new Map}function X$(Z,$){return $.get(Z.toUpperCase())}function $$(Z){if(!s0(Z))return;try{let $=a0(Z,"utf8"),J=JSON.parse($);if(!J||typeof J!=="object")return;let X=new Map;for(let[Q,z]of Object.entries(J)){if(!Q||Q.startsWith("_")||typeof z!=="object"||z===null)continue;let K={name:Q};if(typeof z.min==="number"&&Number.isFinite(z.min))K.min=z.min;if(typeof z.max==="number"&&Number.isFinite(z.max))K.max=z.max;if(typeof z.units==="string"&&z.units)K.units=z.units;X.set(Q.toUpperCase(),K)}return X}catch{return}}var Z$,Z8;var Q$=M(()=>{Z$=t0(e0(import.meta.url)),Z8=[HZ(Z$,"..","data","apm-params.json"),HZ(Z$,"..","..","data","apm-params.json")]});import{existsSync as $8,readFileSync as J8}from"fs";import{join as X8}from"path";function z$(){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 Q8(Z){let $=z$(),J=X8(Z,".hydron","param-rules.yaml");if(!$8(J))return $;try{let X=J8(J,"utf8");return z8($,X)}catch{return $}}function z8(Z,$){let J={ruleset_version:Z.ruleset_version,safety:{...Z.safety},range:{...Z.range}},X=null;for(let Q of $.split(/\r?\n/)){let K=Q.replace(/#.*$/,"").trim();if(!K||K.startsWith("-"))continue;let W=/^ruleset_version\s*:\s*(.+)$/.exec(K);if(W){J.ruleset_version=W[1].trim().replace(/^["']|["']$/g,""),X=null;continue}if(/^safety\s*:\s*$/.test(K)){X="safety";continue}if(/^range\s*:\s*$/.test(K)){X="range";continue}let Y=/^([A-Za-z0-9_]+)\s*:\s*\{(.+)\}\s*$/.exec(K);if(Y&&X){let G=Y[1],B=K8(Y[2]);if(X==="safety"){let U=B.min;if(typeof U==="number")J.safety[G]={min:U}}else{let{min:U,max:O,severity:N}=B;if(typeof U==="number"&&typeof O==="number")J.range[G]={min:U,max:O,severity:N==="CRITICAL"?"CRITICAL":"HIGH"}}}}return J}function K8(Z){let $={};for(let J of Z.split(",")){let X=/^\s*([A-Za-z0-9_]+)\s*:\s*(.+?)\s*$/.exec(J);if(!X)continue;let Q=X[1],z=X[2].replace(/^["']|["']$/g,""),K=Number(z);$[Q]=Number.isFinite(K)&&z!==""?K:z}return $}function W8(Z){let $=new Map;for(let J of Z)$.set(J.name.toUpperCase(),J.value);return $}function b(Z){return{check:Z.check,severity:Z.severity,value:Z.value,threshold_used:Z.threshold_used,ruleset_version:Z.ruleset_version,verdict:Z.verdict,tier:"system",source:Z.source,detail:Z.detail}}function K$(Z,$={}){let J=$.configDir?Q8($.configDir):z$(),X=$.ruleset_version??J.ruleset_version,Q=W8(Z),z=J$($.configDir);return[...Y8(Q,J,X),...G8(Q,X),...H8(Q,J,X,z),...U8(Z,null)]}function Y8(Z,$,J){let X=[],Q={kind:"rule-of-thumb"},z=Z.get("ARMING_CHECK");if(z===void 0)X.push(g("param.safety.arming",J,"ARMING_CHECK absent"));else{let B=z!==0;X.push(b({check:"param.safety.arming",severity:B?"OK":"CRITICAL",value:z,threshold_used:$.safety.ARMING_CHECK?.min??1,verdict:B?"PASS":"FAIL",ruleset_version:J,detail:B?"arming checks enabled":"ARMING_CHECK=0 \u2014 ALL pre-arm safety checks are disabled",source:Q}))}let K=Z.get("BATT_LOW_VOLT"),W=Z.get("BATT_CRT_VOLT");if(K===void 0&&W===void 0)X.push(g("param.safety.battery_failsafe",J,"BATT_LOW_VOLT/BATT_CRT_VOLT absent"));else{let B=(K??0)===0&&(W??0)===0;X.push(b({check:"param.safety.battery_failsafe",severity:B?"CRITICAL":"OK",value:B?0:W??K??0,threshold_used:0,verdict:B?"FAIL":"PASS",ruleset_version:J,detail:B?"battery failsafe not configured (BATT_LOW_VOLT and BATT_CRT_VOLT both 0)":"battery failsafe configured",source:Q}))}let Y=Z.get("FS_THR_ENABLE");if(Y===void 0)X.push(g("param.safety.radio_failsafe",J,"FS_THR_ENABLE absent"));else{let B=Y!==0;X.push(b({check:"param.safety.radio_failsafe",severity:B?"OK":"HIGH",value:Y,threshold_used:$.safety.FS_THR_ENABLE?.min??1,verdict:B?"PASS":"FAIL",ruleset_version:J,detail:B?"radio failsafe enabled":"FS_THR_ENABLE=0 \u2014 radio/throttle failsafe is OFF",source:Q}))}let G=Z.get("FENCE_ENABLE");if(G===void 0)X.push(g("param.safety.fence",J,"FENCE_ENABLE absent"));else{let B=G!==0;X.push(b({check:"param.safety.fence",severity:B?"OK":"HIGH",value:G,threshold_used:$.safety.FENCE_ENABLE?.min??1,verdict:B?"PASS":"FAIL",ruleset_version:J,detail:B?"geofence enabled":"FENCE_ENABLE=0 \u2014 geofence disabled (advisory)",source:Q}))}return X}function G8(Z,$){let J=[],X={kind:"rule-of-thumb"},Q=Z.get("BATT_CRT_VOLT"),z=B8(Z);if(Q===void 0||Q===0||z===null||z<=0)J.push(g("param.consistency.battery_cells",$,"BATT_CRT_VOLT and a cell-count source required"));else{let G=Q/z,B=G>=3&&G<=3.7;J.push(b({check:"param.consistency.battery_cells",severity:B?"OK":"HIGH",value:UZ(G,3),threshold_used:3,verdict:B?"PASS":"FAIL",ruleset_version:$,detail:B?`per-cell critical voltage ${UZ(G,2)}V across ${z}S looks sane`:`per-cell critical voltage ${UZ(G,2)}V (${z}S) outside [3.0,3.7] \u2014 cell count vs BATT_CRT_VOLT inconsistent`,source:X}))}let K=Z.get("FRAME_CLASS"),W=Z.get("FRAME_TYPE");if(K===void 0&&W===void 0)J.push(g("param.consistency.frame",$,"FRAME_CLASS/FRAME_TYPE absent"));else{let G=(K??0)!==0&&(W??0)!==0;J.push(b({check:"param.consistency.frame",severity:G?"OK":"HIGH",value:K??null,threshold_used:1,verdict:G?"PASS":"FAIL",ruleset_version:$,detail:G?`frame configured (CLASS=${K}, TYPE=${W})`:`frame not fully configured (CLASS=${K??"?"}, TYPE=${W??"?"}) \u2014 must be non-zero for a copter`,source:X}))}let Y=Z.get("INS_HNTCH_ENABLE");if(Y===void 0)J.push(g("param.consistency.notch_filter",$,"INS_HNTCH_ENABLE absent"));else J.push(b({check:"param.consistency.notch_filter",severity:"OK",value:Y,threshold_used:null,verdict:"PASS",ruleset_version:$,detail:Y===0?"harmonic notch filter disabled (INS_HNTCH_ENABLE=0) \u2014 advisory; tune if vibration is high":"harmonic notch filter enabled",source:X}));return J}function B8(Z){for(let J of["BATT_CELLS","BATT_N_CELLS","BATT_CELL_COUNT"]){let X=Z.get(J);if(X!==void 0&&X>0)return Math.round(X)}let $=Z.get("BATT_ARM_VOLT");if($!==void 0&&$>0)return Math.round($/3.6);return null}function H8(Z,$,J,X){let Q=[];for(let[z,K]of Object.entries($.range)){let W=Z.get(z.toUpperCase()),Y=`param.range.${z}`;if(W===void 0){Q.push(g(Y,J,`${z} absent`));continue}let G=X$(z,X),B=G!==void 0&&(typeof G.min==="number"||typeof G.max==="number"),U=B&&typeof G.min==="number"?Math.max(K.min,G.min):K.min,O=B&&typeof G.max==="number"?Math.min(K.max,G.max):K.max,N=B&&typeof G.min==="number"?G.min:K.min,P=B&&typeof G.max==="number"?G.max:K.max,_=B?{kind:"datasheet",ref:"apm.pdef.xml"}:{kind:"tuned"},j=W>=U&&W<=O;Q.push(b({check:Y,severity:j?"OK":K.severity,value:W,threshold_used:j?P:W<U?N:P,verdict:j?"PASS":"FAIL",ruleset_version:J,detail:j?`${z}=${W} within [${N},${P}]${B?" (apm.pdef.xml)":""}`:`${z}=${W} outside [${N},${P}]${B?" (apm.pdef.xml)":""}`,source:_}))}return Q}function U8(Z,$){return[]}function g(Z,$,J){return b({check:Z,severity:"OK",value:null,threshold_used:null,verdict:"SKIP",ruleset_version:$,detail:J})}function UZ(Z,$){let J=10**$;return Math.round(Z*J)/J}var W$=M(()=>{Q$()});import{existsSync as V8,readFileSync as L8}from"fs";import{join as O8}from"path";function N8(){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 G$(Z){let $=N8(),J=O8(Z,".hydron","uav-thresholds.yaml");if(!V8(J))return $;try{let X=j8(L8(J,"utf8"));return B$($,X)}catch{return $}}function B$(Z,$){let J={...Z};for(let[X,Q]of Object.entries($)){let z=J[X];if(Q&&typeof Q==="object"&&!Array.isArray(Q)&&z&&typeof z==="object"&&!Array.isArray(z))J[X]=B$(z,Q);else J[X]=Q}return J}function Y$(Z){let $=!1,J=!1;for(let X=0;X<Z.length;X++){let Q=Z[X];if(Q==="'"&&!J)$=!$;else if(Q==='"'&&!$)J=!J;else if(Q==="#"&&!$&&!J)return Z.slice(0,X)}return Z}function H$(Z,$){let J=[],X=0,Q=!1,z=!1,K=0;for(let W=0;W<Z.length;W++){let Y=Z[W];if(Y==="'"&&!z)Q=!Q;else if(Y==='"'&&!Q)z=!z;else if(!Q&&!z){if(Y==="["||Y==="{")X++;else if(Y==="]"||Y==="}")X--;else if(Y===$&&X===0)J.push(Z.slice(K,W)),K=W+1}}return J.push(Z.slice(K)),J}function n(Z){let $=Z.trim();if($==="")return"";if(/^-?\d+(\.\d+)?$/.test($))return Number($);if($==="true")return!0;if($==="false")return!1;if($.startsWith("[")&&$.endsWith("]")){let J=$.slice(1,-1).trim();return J?H$(J,",").map(n):[]}if($.startsWith("{")&&$.endsWith("}"))return U$($);return $.replace(/^["']|["']$/g,"")}function U$(Z){let $=Z.trim().replace(/^\{/,"").replace(/\}$/,""),J={};for(let X of H$($,",")){let Q=X.indexOf(":");if(Q<0)continue;let z=X.slice(0,Q).trim().replace(/^["']|["']$/g,"");if(z)J[z]=n(X.slice(Q+1))}return J}function j8(Z){let $={},J=Z.split(/\r?\n/),X=0;while(X<J.length){let Q=Y$(J[X]);if(X++,!Q.trim()||/^\s/.test(Q))continue;let z=/^([A-Za-z0-9_]+):\s*(.*)$/.exec(Q);if(!z)continue;let K=z[1],W=z[2].trim();if(W.startsWith("{"))$[K]=U$(W);else if(W!=="")$[K]=n(W);else{let Y={};while(X<J.length){let G=Y$(J[X]);if(!G.trim()){X++;continue}if(!/^\s/.test(G))break;X++;let B=/^\s+([A-Za-z0-9_]+):\s*(.*)$/.exec(G);if(B&&B[2].trim()!=="")Y[B[1]]=n(B[2])}$[K]=Y}}return $}var V$=()=>{};function T(Z,$){let J=$.toLowerCase();return Z.columns.findIndex((X)=>X.toLowerCase()===J)}function h(Z){if(typeof Z==="number")return Number.isFinite(Z)?Z:null;if(typeof Z==="bigint")return Number(Z);if(typeof Z==="string"){let $=Number(Z);return Number.isFinite($)?$:null}return null}function q8(Z){if(typeof Z==="bigint")return Z;if(typeof Z==="number"&&Number.isFinite(Z))return BigInt(Math.trunc(Z));if(typeof Z==="string"&&/^-?\d+$/.test(Z.trim()))try{return BigInt(Z.trim())}catch{return null}return null}function f(Z){if(Z===null||Z===void 0)return null;if(typeof Z==="string")return Z;return String(Z)}function i(Z){return`"${Z.replace(/"/g,'""')}"`}function NZ(Z,$){try{return!!Z.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get($)}catch{return!1}}function jZ(Z,$){try{let J=Z.query(`PRAGMA table_info(${i($)})`).all();return new Set(J.map((X)=>X.name))}catch{return new Set}}function c(Z,$){try{let J=Z.query($).get();if(!J)return null;let X=Object.values(J)[0];if(X===null||X===void 0)return null;let Q=typeof X==="bigint"?Number(X):Number(X);return Number.isFinite(Q)?Q:null}catch{return null}}function A8(Z){for(let $ of["ATT","GPS","VIBE","CTUN","IMU"])if(NZ(Z,$)&&jZ(Z,$).has("TimeUS")){let J=c(Z,`SELECT COUNT(*) AS c FROM ${i($)}`);if(J===null||J<=0)continue;let X=c(Z,`SELECT (MAX("TimeUS") - MIN("TimeUS")) AS d FROM ${i($)}`);if(X!==null)return X/1e6}return null}function F8(Z){if(!NZ(Z,"VIBE"))return null;let $=jZ(Z,"VIBE"),J=["VibeX","VibeY","VibeZ"].filter((Q)=>$.has(Q));if(J.length===0)return null;let X=J.map((Q)=>`SELECT MAX(${i(Q)}) AS m FROM "VIBE"`).join(" UNION ALL ");return c(Z,`SELECT MAX(m) AS m FROM (${X})`)}function D8(Z){if(!NZ(Z,"CTUN")||!jZ(Z,"CTUN").has("ThH"))return null;return c(Z,'SELECT AVG("ThH") AS m FROM "CTUN"')}function VZ(Z,$){let J=Z.tables.PARM;if(!J)return null;let X=T(J,"Name"),Q=T(J,"Value");if(X<0||Q<0)return null;let z=$.toLowerCase();for(let K of J.rows)if(f(K[X])?.toLowerCase()===z)return h(K[Q]);return null}function OZ(Z,$){let J=Z.tables.MSG;if(!J)return null;let X=T(J,"Message")>=0?T(J,"Message"):T(J,"Msg");if(X<0)return null;for(let Q of J.rows){let z=f(Q[X]);if(z&&$.test(z))return z}return null}function P8(Z){let $=Z.tables.MSG;if(!$)return null;let J=T($,"Message")>=0?T($,"Message"):T($,"Msg");if(J<0)return null;for(let X of $.rows){let Q=f(X[J]),z=Q&&R8.exec(Q.trim());if(z){let[,K,W,Y,G]=z;return{id:`${W}${Y}${G}`.toUpperCase(),name:`${K}-${W.toUpperCase()}`}}}return null}function T8(Z){let $=P8(Z),J=VZ(Z,"SYSID_THISMAV"),X,Q;if($)X=$.id,Q=$.name;else if(J!==null)X=`sysid-${J}`,Q=OZ(Z,/ArduCopter|ArduPlane|ArduPilot|board/i)??X;else{let W=OZ(Z,/ArduCopter|ArduPlane|ArduPilot|ChibiOS|board/i);X=W??"unknown",Q=W??X}let z,K=VZ(Z,"Q_ENABLE");if(K!==null&&K>=1)z="QuadPlane";else{let W=VZ(Z,"FRAME_CLASS");if(W!==null)z=E8[W]??`class_${W}`}return{kind:"airframe",external_id:X,attrs:{name:Q,frame:z}}}function _8(Z){let $=Z.tables.GPS;if(!$)return null;let J=T($,"GWk"),X=T($,"GMS");if(J<0||X<0)return null;let Q=315964800000,z=18000,K=null;for(let Y of $.rows){let G=h(Y[J]),B=h(Y[X]);if(G===null||B===null||G<=0)continue;let U=Q+G*7*24*3600*1000+B-z;if(K===null||U<K)K=U}if(K===null)return null;let W=new Date(K);return Number.isNaN(W.getTime())?null:W.toISOString()}function I8(Z,$,J){let X=OZ(Z,/ArduCopter|ArduPlane|ArduPilot/);return{kind:"analysis",source_hash:J,logged_at:_8(Z),attrs:{firmware:X??null,duration_s:A8($),pilot_id:null,rc_id:null}}}function S8(Z){let $=Z.tables.PARM;if(!$)return[];let J=T($,"Name"),X=T($,"Value");if(J<0||X<0)return[];let Q=T($,"Default"),z=[];for(let K of $.rows){let W=f(K[J]);if(!W)continue;let Y=h(K[X]);if(Y===null)continue;let G={name:W,value:Y};if(Q>=0){let B=h(K[Q]);G.default=B}z.push(G)}return z}function LZ(Z,$){let J=T(Z,"TimeUS");if(J<0)return 0n;return q8($[J])??0n}function M8(Z){let $=[],J=Z.tables.ERR;if(J){let z=T(J,"Subsys"),K=T(J,"ECode");for(let W of J.rows)$.push({at:LZ(J,W),type:"ERR",payload:{Subsys:z>=0?h(W[z]):null,ECode:K>=0?h(W[K]):null}})}let X=Z.tables.MODE;if(X){let z=T(X,"TimeUS");for(let K of X.rows){let W={};X.columns.forEach((Y,G)=>{if(G===z)return;W[Y]=h(K[G])??f(K[G])}),$.push({at:LZ(X,K),type:"MODE",payload:W})}}let Q=Z.tables.MSG;if(Q){let z=T(Q,"Message")>=0?T(Q,"Message"):T(Q,"Msg");for(let K of Q.rows)$.push({at:LZ(Q,K),type:"MSG",payload:{text:z>=0?f(K[z]):null}})}return $}function C8(Z,$){let J=[],X=F8($);if(X!==null)J.push({name:"vibe_peak",value:X,unit:"m/s/s"});let Q=Z.tables.ERR;if(Q){let K=T(Q,"Subsys"),W=T(Q,"ECode");if(K>=0&&W>=0){let Y=0;for(let G of Q.rows)if(h(G[K])===6&&h(G[W])===1)Y++;J.push({name:"failsafe_count",value:Y})}}let z=D8($);if(z!==null)J.push({name:"hover_thr",value:z});return J}function L$(Z,$,J){return{entity:T8(Z),episode:I8(Z,$,J.sourceHash),params:S8(Z),events:M8(Z),measurements:C8(Z,$)}}var E8,R8;var O$=M(()=>{E8={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"};R8=/^([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 w8,readFile as qZ,writeFile as j$,readdir as q$,stat as y8}from"fs/promises";import{dirname as rJ,join as u}from"path";function A$(Z,$,J){return u(Z,".hydron","observations",$,r(J))}function r(Z){return Z.replace(/[^A-Za-z0-9._-]/g,"_")||"unknown"}function k8(Z,$){return typeof $==="bigint"?$.toString():$}function F$(Z){if(Array.isArray(Z.events))Z.events=Z.events.map(($)=>{let J=$.at,X;if(typeof J==="bigint")X=J;else if(typeof J==="string"&&/^-?\d+$/.test(J))X=BigInt(J);else if(typeof J==="number")X=BigInt(Math.trunc(J));else X=0n;return{...$,at:X}});return Z}function v8(Z){let $=Z.findings??[],J=$.filter((K)=>K.verdict==="FAIL").length,X=$.filter((K)=>K.severity==="CRITICAL"&&K.verdict==="FAIL").length,Q="OK";for(let K of $)if(N$[K.severity]>N$[Q])Q=K.severity;let z=(K)=>Z.measurements?.find((W)=>W.name===K)?.value??null;return{source_hash:Z.episode.source_hash,logged_at:Z.episode.logged_at,ruleset_version:Z.ruleset_version,anomalies:J,critical:X,vibe_peak:z("vibe_peak"),failsafe_count:z("failsafe_count"),worst_severity:Q,...Z.tags&&Z.tags.length>0?{tags:Z.tags}:{}}}async function h8(Z){let $;try{$=await qZ(Z,"utf8")}catch{return[]}let J=[];for(let X of $.split(`
5
- `)){let Q=X.trim();if(!Q)continue;try{J.push(JSON.parse(Q))}catch{}}return J}async function b8(Z,$){let J=u(Z,"index.jsonl"),X=await h8(J),Q=v8($),z=X.filter((K)=>K.source_hash!==Q.source_hash);z.push(Q),await j$(J,z.map((K)=>JSON.stringify(K)).join(`
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(`
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
- `,"utf8")}async function D$(Z,$){let J=A$($.projectDir,$.workspace,Z.entity.external_id);await w8(J,{recursive:!0});let X=u(J,`${r(Z.episode.source_hash)}.json`);return await j$(X,JSON.stringify(Z,k8,2),"utf8"),await b8(J,Z),X}async function E$(Z){let $=A$(Z.projectDir,Z.workspace,Z.sysid),J;try{J=await q$($)}catch{return null}let X=`${r(Z.excludeSourceHash)}.json`,Q=J.filter((K)=>K.endsWith(".json")&&K!==X),z=null;for(let K of Q){let W=u($,K),Y;try{let O=await qZ(W,"utf8");Y=F$(JSON.parse(O))}catch{continue}let G=0;try{G=(await y8(W)).mtimeMs}catch{}let B=Y.episode?.logged_at?Date.parse(Y.episode.logged_at):NaN,U=Number.isNaN(B)?-1/0:B;if(z===null||U>z.loggedAt||U===z.loggedAt&&G>z.mtime)z={doc:Y,loggedAt:U,mtime:G}}return z?.doc??null}async function g8(Z,$,J){let X=u(Z,".hydron","observations",$),Q=`${r(J)}.json`,z;try{z=await q$(X)}catch{return null}for(let K of z){let W=u(X,K,Q),Y;try{let G=await qZ(W,"utf8");Y=F$(JSON.parse(G))}catch{continue}return{path:W,doc:Y}}return null}async function R$(Z){let $=await g8(Z.projectDir,Z.workspace,Z.flight_id);if(!$)return[];return($.doc.findings??[]).filter((J)=>J.origin==="agent")}var N$;var P$=M(()=>{N$={OK:0,HIGH:1,CRITICAL:2}});function f8(Z,$){let J=new Map;for(let Q of Z)J.set(Q.name,Q.value);let X=[];for(let Q of $){let z=J.get(Q.name);if(z===void 0)continue;if(z!==Q.value)X.push({name:Q.name,old:z,new:Q.value})}return X}function u8(Z,$){return f8(Z.params??[],$.params??[])}function x8(Z,$){let J=new Map;for(let Q of Z.findings??[])if(Q.tier==="system")J.set(Q.check,Q);let X=[];for(let Q of $.findings??[]){if(Q.tier!=="system")continue;let z=J.get(Q.check);if(!z)continue;if(z.severity!==Q.severity)X.push({check:Q.check,old:z.severity,new:Q.severity})}return X}function T$(Z,$){return{param_changes:u8(Z,$),finding_changes:x8(Z,$)}}var S$={};DZ(S$,{analyzeFlight:()=>c8});import{createHash as m8}from"crypto";import{open as I$,stat as p8}from"fs/promises";import{resolve as d8}from"path";async function l8(Z){let $=await I$(Z,"r");try{let J=Buffer.alloc(2);return await $.read(J,0,2,0),J[0]===_$[0]&&J[1]===_$[1]}finally{await $.close()}}async function n8(Z){let $=await I$(Z,"r");try{let J=m8("sha256"),X=Buffer.alloc(1048576),Q=0;for(;;){let{bytesRead:z}=await $.read(X,0,X.length,Q);if(z===0)break;J.update(X.subarray(0,z)),Q+=z}return J.digest("hex").slice(0,16)}finally{await $.close()}}function i8(Z){let $=Z.filter((Q)=>Q.verdict==="FAIL").length,J=Z.filter((Q)=>Q.severity==="CRITICAL"&&Q.verdict==="FAIL").length,X=Z.filter((Q)=>Q.verdict==="PASS").length;return{total:Z.length,passed:X,anomalies:$,critical:J}}async function c8(Z,$){if(await p8(Z),!await l8(Z))throw Error(`Not an ArduPilot DataFlash .bin (missing 0xA3 0x95 header): ${Z}`);let J=await n8(Z),X=G$($.configDir??$.projectDir),{log:Q,db:z,cleanup:K}=await m(Z,J,{configDir:$.configDir??$.projectDir});try{let W=L$(Q,z,{sourceHash:J});W.episode.attrs.source_path=d8(Z);let Y=rZ(Q);W.episode.attrs.vehicle_type=Y;let G=tZ(z,X,{vehicleType:Y});G=[...G,...K$(W.params,{configDir:$.configDir??$.projectDir,ruleset_version:X.ruleset_version})];let B=await R$({projectDir:$.projectDir,workspace:$.workspace,flight_id:J});G=[...G,...B];let U={schema_version:1,entity:W.entity,episode:W.episode,params:W.params,findings:G,events:W.events,measurements:W.measurements,ruleset_version:X.ruleset_version},O=await E$({projectDir:$.projectDir,workspace:$.workspace,sysid:W.entity.external_id,excludeSourceHash:J}),N=await D$(U,{projectDir:$.projectDir,workspace:$.workspace}),P={flight_id:J,vehicle_id:W.entity.external_id,metadata:{airframe:W.entity.attrs.name??W.entity.external_id,firmware:W.episode.attrs.firmware??null,duration_s:W.episode.attrs.duration_s??null},partial_decode:Q.partial,decoded_until:Q.decodedUntil,checks:G,summary:i8(G),ruleset_version:X.ruleset_version};if(O){let{param_changes:_,finding_changes:j}=T$(O,U);P.comparison={prior_flight_id:O.episode.source_hash,param_changes:_,finding_changes:j,narration:{claims:[]}}}return{report:P,doc:U,episodePath:N}}finally{K()}}var _$;var M$=M(()=>{WZ();eZ();W$();V$();O$();P$();_$=[163,149]});var y$={};DZ(y$,{sanitizeQuery:()=>w$,runUavQuery:()=>a8,renderQueryResult:()=>t8});import{readdir as r8,readFile as o8}from"fs/promises";import{join as C$}from"path";async function s8(Z,$,J){let X=C$(Z,".hydron","observations",$),Q;try{Q=await r8(X)}catch{throw Error(`No observation store at ${X}. Run uav_analyze first.`)}for(let z of Q){let K=C$(X,z,`${J}.json`);try{let Y=JSON.parse(await o8(K,"utf8"))?.episode?.attrs?.source_path;if(typeof Y==="string"&&Y)return Y;throw Error(`Episode ${J} has no source_path; re-run uav_analyze to record it.`)}catch(W){if(W.code==="ENOENT")continue;throw W}}throw Error(`flight_id ${J} not found in the observation store. Run uav_analyze first.`)}function w$(Z){let $=Z.trim();$=$.replace(/^```(?:sql)?\s*/i,"").replace(/\s*```$/,"").trim();for(;;){let Q=$;if($=$.replace(/^--[^\n]*\n?/,"").replace(/^\/\*[\s\S]*?\*\//,"").trimStart(),$===Q)break}if($=$.replace(/;\s*$/,""),$.includes(";"))throw Error("Only a single statement is allowed (no ';').");let J=$.replace(/^\(+\s*/,"");if(!(/^\s*(select|with|values)\b/i.test(J)||/^\s*explain\b/i.test($)||/^\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($)))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($))throw Error("Write/DDL keyword detected \u2014 uav_query is read-only.");if(!/\blimit\b/i.test($))$+=` LIMIT ${o}`;return $}async function a8(Z){let $=w$(Z.query),J=await s8(Z.projectDir,Z.workspace,Z.flight_id),{db:X,cleanup:Q}=await m(J,Z.flight_id);try{X.exec?.("PRAGMA query_only = ON");let K=X.query($).all(),W=K.length?Object.keys(K[0]):[],G=K.slice(0,o).map((B)=>W.map((U)=>B[U]));return{columns:W,rows:G,truncated:K.length>o}}finally{Q()}}function t8(Z){if(!Z.columns.length)return"(no rows)";let $=Z.columns.join(" | "),J=Z.rows.slice(0,50).map((Q)=>Q.map((z)=>typeof z==="bigint"?z.toString():String(z)).join(" | ")).join(`
8
- `),X=Z.rows.length>50?`
9
- \u2026 ${Z.rows.length-50} more rows`:Z.truncated?`
10
- (capped at ${o} rows)`:"";return`${$}
11
- ${J}${X}`}var o=1e4;var k$=M(()=>{WZ()});self.onmessage=async(Z)=>{let $=Z.data;try{let J;if($.op==="analyze"){let{analyzeFlight:X}=await Promise.resolve().then(() => (M$(),S$));J=await X($.binPath,$.opts)}else if($.op==="query"){let{runUavQuery:X}=await Promise.resolve().then(() => (k$(),y$));J=await X($.opts)}else throw Error("unknown worker op");self.postMessage({ok:!0,result:J})}catch(J){self.postMessage({ok:!1,error:J instanceof Error?J.message:String(J)})}};
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)})}};
@@ -46,7 +46,10 @@ never to author a verdict from raw numbers.
46
46
  genuinely new (`supersedes_id` to replace a stale one). Only ABSOLUTE-bound findings the
47
47
  deterministic checks did not already cover — never a relative-only one.
48
48
  - **Bench / live vehicle** → `serial_*` (watch/drive the FC console) and the `mavlink` MCP
49
- (read params/telemetry; gated param writes) when a link is configured.
49
+ (read params/telemetry; `param_set`/`param_set_batch`) when a link is configured. ⚠ param
50
+ writes are **enabled by default and go to whatever is on the connect target — possibly a real
51
+ airframe**. Always state the exact param + old→new value and get explicit confirmation before
52
+ writing; never batch-write a tuning set without the user agreeing to it first.
50
53
 
51
54
  ## Load the reference that matches the task
52
55
 
@@ -65,8 +65,10 @@ These params are **starting values**, not a verified tune. They must be reviewed
65
65
  human (or the gating subagent) before they touch a vehicle. Critically, this module
66
66
  only *recommends* — it has no path to a flight controller.
67
67
 
68
- **Pushing params is a separate, gated action.** `/uav-tune` (or the `uav_tune` tool) only
68
+ **Pushing params is a separate, explicit action.** `/uav-tune` (or the `uav_tune` tool) only
69
69
  recommends — confirm the recommendation against the airframe and check the ranges, then
70
- write parameters over the gated MAVLink param link (`--allow-param-write`). After applying,
70
+ write parameters over the MAVLink param link (`param_set` / `param_set_batch`, available by
71
+ default). ⚠ that link writes to whatever is on the connect target, which may be a **live
72
+ vehicle**: state each param and its old→new value and get explicit confirmation first. After applying,
71
73
  re-fly and re-run `recommendNotch` on the new
72
74
  log to confirm the peak dropped — the same FFT→notch loop, closed automatically.