@h2loop/uav 1.1.0 → 1.2.1

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