@h2loop/uav 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -16
- package/USAGE.md +47 -30
- package/bridge/requirements.txt +5 -1
- package/mcp.json +1 -7
- package/package.json +1 -1
- package/plugins/index.js +36 -36
- package/plugins/worker/worker-entry.js +5 -9
- package/skills/uav/SKILL.md +4 -1
- package/skills/uav/references/tuning.md +4 -2
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
`))!==-1){let
|
|
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
|
|
2
|
+
var M=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};function Ee(){let e=process.env.UAV_DECODE_MAX_CPU;if(!e)return;let t=Number(e);return Number.isFinite(t)&&t>0&&t<1?t:void 0}async function Ae(e,t){if(!t||e<=0)return;let n=Math.min(e*(1/t-1),250);if(n>=1)await Vt(n)}var Vt=(e)=>new Promise((t)=>setTimeout(t,e));var ke;var Te=M(()=>{ke={a:{kind:"str",width:64},b:{kind:"i8",width:1},B:{kind:"u8",width:1},h:{kind:"i16",width:2},H:{kind:"u16",width:2},i:{kind:"i32",width:4},I:{kind:"u32",width:4},f:{kind:"f32",width:4},d:{kind:"f64",width:8},n:{kind:"str",width:4},N:{kind:"str",width:16},Z:{kind:"str",width:64},c:{kind:"i16",width:2,scale:0.01},C:{kind:"u16",width:2,scale:0.01},e:{kind:"i32",width:4,scale:0.01},E:{kind:"u32",width:4,scale:0.01},L:{kind:"i32",width:4,scale:0.0000001},M:{kind:"u8",width:1},q:{kind:"i64",width:8},Q:{kind:"u64",width:8}}});import{open as Bt}from"fs/promises";function Xt(e){return(t,n)=>{let r="",s=n+e;for(let i=n;i<s;i++){let o=t.getUint8(i);if(o===0)break;r+=String.fromCharCode(o)}return r}}function qt(e){let t=e.scale;switch(e.kind){case"i8":return t===void 0?(n,r)=>n.getInt8(r):(n,r)=>n.getInt8(r)*t;case"u8":return t===void 0?(n,r)=>n.getUint8(r):(n,r)=>n.getUint8(r)*t;case"i16":return t===void 0?(n,r)=>n.getInt16(r,!0):(n,r)=>n.getInt16(r,!0)*t;case"u16":return t===void 0?(n,r)=>n.getUint16(r,!0):(n,r)=>n.getUint16(r,!0)*t;case"i32":return t===void 0?(n,r)=>n.getInt32(r,!0):(n,r)=>n.getInt32(r,!0)*t;case"u32":return t===void 0?(n,r)=>n.getUint32(r,!0):(n,r)=>n.getUint32(r,!0)*t;case"f32":return(n,r)=>n.getFloat32(r,!0);case"f64":return(n,r)=>n.getFloat64(r,!0);case"i64":return(n,r)=>n.getBigInt64(r,!0);case"u64":return(n,r)=>n.getBigUint64(r,!0);case"str":return Xt(e.width)}}function Wt(e,t){let n=[],r=[];for(let i of e){let o=ke[i];if(!o)return{readers:[],widths:[],ok:!1,timeIdx:-1};n.push(qt(o)),r.push(o.width)}let s=t.indexOf("TimeUS");return{readers:n,widths:r,ok:!0,timeIdx:s}}async function Ce(e,t,n){let r=n??Ee(),s=new Map,i={},o=!1,a=null,c=null,l=4194304,u=await Bt(e,"r");try{let f=Buffer.allocUnsafe(l),p=new Uint8Array(0),g=0,k=!1;while(!k){let{bytesRead:S}=await u.read(f,0,l,g);g+=S,k=S===0;let y;if(S===0)y=p;else if(p.length===0)y=f.subarray(0,S);else y=new Uint8Array(p.length+S),y.set(p,0),y.set(f.subarray(0,S),p.length);let h=new DataView(y.buffer,y.byteOffset,y.byteLength),m=y.length,v=k,b=performance.now(),w=0;while(w+3<=m){if(y[w]!==jt||y[w+1]!==Ut){w+=1;continue}let E=y[w+2],F=w+3;if(E===Gt){if(F+Se>m){if(v)o=!0;break}let O=y[F],ve=y[F+1],U=Z(y,F+2,4),$t=Z(y,F+6,16),Q=Z(y,F+22,64).split(",").filter((Ht)=>Ht.length>0),{readers:Ot,widths:xt,ok:Lt,timeIdx:Nt}=Wt($t,Q);s.set(O,{name:U,length:ve,columns:Q,ok:Lt,payloadLen:ve-3,readers:Ot,widths:xt,timeIdx:Nt}),t.onFmt(U,Q),i[U]=(i[U]??0)+1,w+=3+Se;continue}let R=s.get(E);if(R===void 0){w+=1;continue}let P=R.payloadLen;if(F+P>m){if(v)o=!0;break}if(i[R.name]=(i[R.name]??0)+1,!R.ok){w+=3+P;continue}let{readers:z,widths:Dt}=R,Y=Array(z.length),we=F;for(let O=0;O<z.length;O++)Y[O]=z[O](h,we),we+=Dt[O];if(t.onRow(R.name,Y),R.timeIdx>=0){let O=Y[R.timeIdx];if(typeof O==="bigint")c=O}w+=3+P}if(p=y.slice(w),await Ae(performance.now()-b,r),k)break}}finally{await u.close()}if(o)a=c;return{partial:o,decodedUntil:a,messageCounts:i}}function Re(e,t,n){let r=e[t];if(!r)e[t]={columns:n,rows:[]};else r.columns=n}async function Me(e){let t={},n=await Ce(e,{onFmt:(r,s)=>Re(t,r,s),onRow:(r,s)=>{t[r].rows.push(s)}});return{partial:n.partial,decodedUntil:n.decodedUntil,tables:t,messageCounts:n.messageCounts}}async function Ie(e,t,n={}){let r=n.retain??new Set,s=5000,i={},o=new Map,a=await Ce(e,{onFmt:(c,l)=>{if(Re(i,c,l),t.table(c,l),!o.has(c))o.set(c,[])},onRow:(c,l)=>{let u=o.get(c);if(u){if(u.push(l),u.length>=5000)t.rows(c,u),u.length=0}if(r.has(c))i[c].rows.push(l)}});for(let[c,l]of o)if(l.length)t.rows(c,l);return{partial:a.partial,decodedUntil:a.decodedUntil,tables:i,messageCounts:a.messageCounts}}function Z(e,t,n){let r="",s=t+n;for(let i=t;i<s;i++){let o=e[i];if(o===0)break;r+=String.fromCharCode(o)}return r}var jt=163,Ut=149,Gt=128,Se=86;var Fe=M(()=>{Te()});function Kt(){let e=process.env.UAV_PYTHON?.trim();if(e)return[[e]];return process.platform==="win32"?[["py","-3"],["python"],["python3"]]:[["python3"],["python"]]}async function zt(e){try{return await Bun.spawn([...e,"-c","import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)"],{stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited===0}catch{return!1}}async function Yt(){if(Pe)return ee;for(let e of Kt())if(await zt(e)){ee=e;break}return Pe=!0,ee}async function G(){let e=await Yt();if(!e)throw Error(Jt);return e}var Jt,ee=null,Pe=!1;var te=M(()=>{Jt="no working Python 3 interpreter found. Install Python >= 3.8 and make sure `python3` "+"(macOS/Linux) or `python` (Windows \u2014 tick \u201CAdd python.exe to PATH\u201D in the installer) runs "+"from a terminal, or set UAV_PYTHON to the interpreter's full path."});import{fileURLToPath as Qt}from"url";function De(e){return typeof e==="object"&&e!==null&&"_summary"in e}function tn(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function ne(e){let t=await G();if(await Bun.spawn([...t,"-c","import pymavlink"],{stdout:"ignore",stderr:"ignore"}).exited!==0)throw Error(`pymavlink not found \u2014 ${t.join(" ")} -m pip install pymavlink`);let r=Bun.spawn([...t,Zt,e],{stdout:"pipe",stderr:"pipe"}),s=new Map,i={},o=!1,a=null,c=null,l=!1;function u(h){let m=s.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},s.set(h,m);return m}function f(h){let m=h.t,v=u(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=en.has(E)?tn(R):R;if(w[F]=P,E==="TimeUS"&&typeof P==="bigint")c=P}v.rows.push(w)}let p=new TextDecoder,g="";for await(let h of r.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
3
|
+
`))!==-1){let v=g.slice(0,m);if(g=g.slice(m+1),v.length===0)continue;let b;try{b=JSON.parse(v)}catch{o=!0;continue}if(De(b)){l=!0;for(let[w,E]of Object.entries(b._summary.counts))i[w]=E;if(b._summary.partial)o=!0}else f(b)}}g+=p.decode();let k=g.trim();if(k.length>0)try{let h=JSON.parse(k);if(De(h)){l=!0;for(let[m,v]of Object.entries(h._summary.counts))i[m]=v;if(h._summary.partial)o=!0}else f(h)}catch{o=!0}let S=await r.exited;if(S!==0){if(!l){let h=(await new Response(r.stderr).text()).trim();throw Error(`pymavlink decode failed (exit ${S})${h?`: ${h}`:""}`)}o=!0}if(!l)o=!0;if(o)a=c;let y={};for(let[h,m]of s)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of s)if(i[h]===void 0)i[h]=m.rows.length;return{partial:o,decodedUntil:a,tables:y,messageCounts:i}}var Zt,en;var $e=M(()=>{te();Zt=Qt(new URL("./mavdump.py",import.meta.url)),en=new Set(["TimeUS","TimeMS"])});import{fileURLToPath as nn}from"url";function on(e){return typeof e==="object"&&e!==null&&"_summary"in e}function an(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e))return BigInt(e);return 0n}async function cn(e){let t=()=>Bun.spawn([...e,"-c","import pyulog"],{stdout:"ignore",stderr:"ignore"}).exited;if(await t()===0)return;if(await Bun.spawn([...e,"-m","pip","install","--quiet","pyulog"],{stdout:"ignore",stderr:"ignore"}).exited,await t()!==0)throw Error(`pyulog not found \u2014 ${e.join(" ")} -m pip install pyulog`)}async function Oe(e){let t=await G();await cn(t);let n=Bun.spawn([...t,rn,e],{stdout:"pipe",stderr:"pipe"}),r=new Map,s={},i=!1,o=null,a=null,c=!1;function l(h){let m=r.get(h);if(!m)m={columns:[],colIndex:new Map,rows:[]},r.set(h,m);return m}function u(h){let m=h.t,v=l(m),b=h.f;for(let E of Object.keys(b))if(!v.colIndex.has(E))v.colIndex.set(E,v.columns.length),v.columns.push(E);let w=Array(v.columns.length).fill(null);for(let E of Object.keys(b)){let F=v.colIndex.get(E),R=b[E],P=sn.has(E)?an(R):R;if(w[F]=P,E==="timestamp"&&typeof P==="bigint")a=P}v.rows.push(w)}function f(h){if(h.length===0)return;let m;try{m=JSON.parse(h)}catch{i=!0;return}if(on(m)){c=!0;for(let[v,b]of Object.entries(m._summary.counts))s[v]=b;if(m._summary.partial)i=!0}else u(m)}let p=new TextDecoder,g="";for await(let h of n.stdout){g+=p.decode(h,{stream:!0});let m;while((m=g.indexOf(`
|
|
4
|
+
`))!==-1)f(g.slice(0,m)),g=g.slice(m+1)}g+=p.decode();let k=g.trim();if(k.length>0)f(k);let S=await n.exited;if(S!==0){if(!c){let h=(await new Response(n.stderr).text()).trim();throw Error(`ulog decode failed (exit ${S})${h?`: ${h}`:""}`)}i=!0}if(!c)i=!0;if(i)o=a;let y={};for(let[h,m]of r)y[h]={columns:m.columns,rows:m.rows};for(let[h,m]of r)if(s[h]===void 0)s[h]=m.rows.length;return{partial:i,decodedUntil:o,tables:y,messageCounts:s}}var rn,sn;var xe=M(()=>{te();rn=nn(new URL("./ulog.py",import.meta.url)),sn=new Set(["timestamp","timestamp_sample"])});import{existsSync as Le,readFileSync as ln}from"fs";import{mkdtemp as un,rm as dn}from"fs/promises";import{tmpdir as fn}from"os";import{basename as re,join as se}from"path";function Ne(e){if(!e)return[];let t=se(e,".hydron","uav-format-converters.json");if(!Le(t))return[];try{let n=JSON.parse(ln(t,"utf8"));return Array.isArray(n.converters)?n.converters.filter((r)=>r&&r.match&&r.command):[]}catch{return[]}}function He(e,t){for(let n of t)try{if(new RegExp(n.match,"i").test(e))return n}catch{}return null}async function Ve(e,t){let n=await un(se(fn(),"uav-convert-")),r=re(e).replace(/\.[^.]+$/,""),s=se(n,r+(t.produces??".bin")),i=t.command.replaceAll("{input}",e).replaceAll("{output}",s),o=()=>dn(n,{recursive:!0,force:!0});try{let a=process.platform==="win32"?["cmd.exe","/d","/s","/c",i]:["bash","-lc",i],c=Bun.spawn(a,{stdout:"pipe",stderr:"pipe"}),l=await c.exited;if(l!==0){let u=(await new Response(c.stderr).text()).trim().slice(0,300);throw Error(`format converter failed (exit ${l}) for ${re(e)}: ${u}`)}if(!Le(s))throw Error(`format converter produced no output for ${re(e)}`);return{out:s,cleanup:o}}catch(a){throw await o(),a}}var Be=()=>{};import{Database as mn}from"bun:sqlite";import{tmpdir as hn}from"os";import{join as pn}from"path";import{existsSync as je,unlinkSync as Ue}from"fs";function Xe(e){let t=pn(hn(),`uav-${e}-${process.pid}-${gn++}.sqlite`);try{if(je(t))Ue(t)}catch{}let n=new mn(t);return n.exec("PRAGMA page_size = 8192"),n.query("PRAGMA journal_mode = MEMORY").get(),n.exec("PRAGMA synchronous = OFF"),n.exec("PRAGMA temp_store = FILE"),n.exec("PRAGMA cache_size = -65536"),{db:n,cleanup(){try{n.close()}catch{}try{if(je(t))Ue(t)}catch{}}}}function oe(e){let t=new Map,n=new Map;return{table(r,s){if(t.has(r)||s.length===0)return;e.run(`CREATE TABLE ${ie(r)} (${s.map(ie).join(", ")})`);let i=s.map(()=>"?").join(", ");t.set(r,e.query(`INSERT INTO ${ie(r)} VALUES (${i})`)),n.set(r,s.length)},rows(r,s){let i=t.get(r),o=n.get(r);if(!i||o===void 0||s.length===0)return;let a=e.transaction((c)=>{for(let l of c){let u=Array(o);for(let f=0;f<o;f++){let p=l[f];u[f]=p===void 0?null:p}i.run(...u)}});for(let c=0;c<s.length;c+=Ge)a(s.slice(c,c+Ge))}}}function qe(e,t){let n=oe(e);for(let[r,s]of Object.entries(t.tables)){if(s.columns.length===0)continue;if(n.table(r,s.columns),s.rows.length)n.rows(r,s.rows)}}var gn=0,ie=(e)=>`"${e.replace(/"/g,'""')}"`,Ge=5000;var We=()=>{};async function j(e,t="flight",n){let r=He(e,Ne(n?.configDir));if(r){let{out:o,cleanup:a}=await Ve(e,r);try{return await j(o,t)}finally{await a()}}let{db:s,cleanup:i}=Xe(t);try{let o=e.toLowerCase();if(o.endsWith(".bin"))return{log:await Ie(e,oe(s),{retain:yn}),db:s,cleanup:i};let a;if(o.endsWith(".ulog"))a=await Oe(e);else if(o.endsWith(".tlog")||o.endsWith(".log"))a=await ne(e);else try{a=await Me(e)}catch{a=await ne(e)}return qe(s,a),{log:a,db:s,cleanup:i}}catch(o){throw i(),o}}var yn;var ae=M(()=>{Fe();$e();xe();Be();We();yn=new Set(["PARM","MSG","GPS","ERR","MODE"])});function ce(e,t){let n=e.tables.PARM;if(!n)return null;let r=n.columns.findIndex((o)=>o.toLowerCase()==="name"),s=n.columns.findIndex((o)=>o.toLowerCase()==="value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(String(o[r]).toLowerCase()===i){let a=Number(o[s]);return Number.isFinite(a)?a:null}return null}function bn(e){let t=e.tables.MSG;if(!t)return"";let n=t.columns.findIndex((r)=>/message|msg/i.test(r));if(n<0)return"";for(let r of t.rows){let s=String(r[n]??"");if(/Ardu(Copter|Plane|Sub|Rover)|PX4/i.test(s))return s}return""}function Je(e){let t=ce(e,"Q_ENABLE");if(t!==null&&t>=1||e.tables.QUIK||e.tables.AETR){if(e.tables.MOTB||ce(e,"FRAME_CLASS")!==null||e.tables.ARSP)return"vtol"}if(t!==null&&t>=1)return"vtol";let n=bn(e);if(/ArduPlane/i.test(n))return"fixedwing";if(/ArduCopter/i.test(n))return"multirotor";if(ce(e,"FRAME_CLASS")!==null)return"multirotor";if(e.tables.ARSP&&!e.tables.MOTB)return"fixedwing";if(e.tables.MOTB||e.tables.RATE)return"multirotor";return"unknown"}function X(e){return e===void 0||e==="multirotor"||e==="vtol"||e==="unknown"}function Ke(e){return e==="fixedwing"||e==="vtol"}function I(e){return`"${e.replace(/"/g,'""')}"`}function _(e,t){let n=e.db.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;return Number(r)}function D(e,t){try{let n=e.db.query(`PRAGMA table_info(${I(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function C(e,t,n){return D(e,t).has(n)}function Ye(e,t){for(let n of t)if(e.hasTable(n))return n;return null}function d(e,t,n){return{check:e,severity:"OK",value:null,threshold_used:null,ruleset_version:t.ruleset_version,verdict:"SKIP",tier:"system",...n?{detail:n}:{}}}function A(e){return{check:e.check,severity:e.failed?e.failSeverity:"OK",value:e.value,threshold_used:e.threshold_used,ruleset_version:e.thresholds.ruleset_version,verdict:e.failed?"FAIL":"PASS",tier:"system",...e.source?{source:e.source}:{},...e.detail?{detail:e.detail}:{}}}function Sn(e,t,n){let r=Object.values(e);if(t<=0||r.length===0)return"";let s=[...r].sort((l,u)=>u-l),i=s[0],o=s.length>1?s[1]:0;if(s.length>=2&&o>0&&i>=2*o)return" | cause: likely sensor/mounting alignment (one axis dominates)";let c=s.length>=2&&i<=1.5*(s[s.length-1]||i);if(n>0||c)return" | cause: likely mechanical degradation (props/bearings/frame)";return""}function Qe(e,t,n){let r=new Set;try{let o=e.query("SELECT name FROM sqlite_master WHERE type='table'").all();for(let a of o)r.add(a.name)}catch{}let s={db:e,thresholds:t,hasTable:(o)=>r.has(o),vehicleType:n?.vehicleType},i=[];for(let{id:o,run:a}of qn)try{i.push(a(s))}catch(c){let l=c instanceof Error?c.message:String(c);i.push(d(o,t,`check error: ${l}`))}return i}var _n=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("ERR"))return d("battery",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("battery",e.thresholds,"ERR present but Subsys/ECode columns absent");let n=t?.err_subsys??6,r=t?.err_ecode??1,s=_(e,`SELECT COUNT(*) FROM "ERR" WHERE "Subsys"=${n} AND "ECode"=${r}`)??0;return A({check:"battery",thresholds:e.thresholds,failed:s>0,failSeverity:"CRITICAL",value:s,threshold_used:0,source:t?.source,detail:s>0?`${s} battery failsafe ERR event(s) (Subsys=${n} ECode=${r})`:void 0})},wn=(e)=>{let t=e.thresholds.attitude;if(!e.hasTable("ATT"))return d("attitude",e.thresholds);for(let o of["DesRoll","Roll","DesPitch","Pitch"])if(!C(e,"ATT",o))return d("attitude",e.thresholds,`ATT missing column ${o}`);let n=t?.max_deg??5,r=_(e,'SELECT MAX(ABS("DesRoll"-"Roll")) FROM "ATT"'),s=_(e,'SELECT MAX(ABS("DesPitch"-"Pitch")) FROM "ATT"'),i=Math.max(r??0,s??0);return A({check:"attitude",thresholds:e.thresholds,failed:i>n,failSeverity:"HIGH",value:i,threshold_used:n,source:t?.source,detail:`peak roll err ${(r??0).toFixed(2)}\xB0, pitch err ${(s??0).toFixed(2)}\xB0`})},vn=(e)=>{let t=e.thresholds.altitude;if(!e.hasTable("CTUN"))return d("altitude",e.thresholds);if(!C(e,"CTUN","DAlt")||!C(e,"CTUN","Alt"))return d("altitude",e.thresholds,"CTUN missing DAlt/Alt columns");let n=t?.max_m??2,r=_(e,'SELECT MAX(ABS("DAlt"-"Alt")) FROM "CTUN"');return A({check:"altitude",thresholds:e.thresholds,failed:(r??0)>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},En=(e)=>{let t=e.thresholds.hover;if(!X(e.vehicleType))return d("hover",e.thresholds,`n/a for ${e.vehicleType} (no hover throttle)`);if(!e.hasTable("CTUN"))return d("hover",e.thresholds);if(!C(e,"CTUN","ThH"))return d("hover",e.thresholds,"CTUN missing ThH column");let n=t?.band??[0.25,0.75],[r,s]=n,i=_(e,'SELECT AVG("ThH") FROM "CTUN"'),o=i===null?!1:i<r||i>s;return A({check:"hover",thresholds:e.thresholds,failed:o,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`mean hover throttle ${(i??0).toFixed(3)} vs band [${r}, ${s}]`})},ze=2000,An=(e)=>{if(!X(e.vehicleType))return d("rcou",e.thresholds,`n/a for ${e.vehicleType} (control surfaces, not motor mix)`);if(!e.hasTable("RCOU"))return d("rcou",e.thresholds);let t=D(e,"RCOU"),n=[];for(let i=1;i<=8;i++)if(t.has(`C${i}`))n.push(`C${i}`);if(n.length===0)return d("rcou",e.thresholds,"RCOU has no C1..C8 channels");let r=-1/0,s=[];for(let i of n){let o=_(e,`SELECT MAX(${I(i)}) FROM "RCOU"`);if(o===null)continue;if(o>r)r=o;if(o>=ze)s.push(`${i}=${o}`)}if(r===-1/0)r=0;return A({check:"rcou",thresholds:e.thresholds,failed:s.length>0,failSeverity:"HIGH",value:r,threshold_used:ze,detail:s.length>0?`motor output(s) pegged at max: ${s.join(", ")}`:void 0})},le=1000,ue=2000,kn=(e)=>{if(!e.hasTable("RCIN"))return d("rcin",e.thresholds);if(!C(e,"RCIN","C3"))return d("rcin",e.thresholds,"RCIN missing C3 column");let t=_(e,'SELECT MIN("C3") FROM "RCIN"'),n=_(e,'SELECT MAX("C3") FROM "RCIN"'),r=t!==null&&t<le||n!==null&&n>ue,s=n;if(t!==null&&t<le)s=t;return A({check:"rcin",thresholds:e.thresholds,failed:r,failSeverity:"HIGH",value:s,threshold_used:ue,detail:`RCIN C3 range [${t??"\u2014"}, ${n??"\u2014"}] vs [${le}, ${ue}]`})},Tn=(e)=>{let t=e.thresholds.vibration;if(!e.hasTable("VIBE"))return d("vibration",e.thresholds);let n=D(e,"VIBE"),r=["VibeX","VibeY","VibeZ"].filter((f)=>n.has(f));if(r.length===0)return d("vibration",e.thresholds,"VIBE has no VibeX/Y/Z columns");let s=t?.max_ms2??30,i={},o=-1/0;for(let f of r){let g=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`)??0;if(i[f]=g,g>o)o=g}if(o===-1/0)o=0;let a=["Clip","Clip0","Clip1","Clip2"].filter((f)=>n.has(f)),c=0;for(let f of a){let p=_(e,`SELECT MAX(${I(f)}) FROM "VIBE"`);if(p!==null&&p>c)c=p}let l=a.length>0?` | clipping MAX=${c}${c>0?" (CLIP EVENTS)":""}`:"",u=Sn(i,o,c);return A({check:"vibration",thresholds:e.thresholds,failed:o>=s,failSeverity:"HIGH",value:o,threshold_used:s,source:t?.source,detail:`peak vibe ${o} m/s\xB2 (axes ${r.join("/")})${l}${u}`})},Cn=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag",e.thresholds);if(!C(e,"MAG","Health"))return d("mag",e.thresholds,"MAG missing Health column");let n=t?.min??1,r=_(e,'SELECT MIN("Health") FROM "MAG"');return A({check:"mag",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source})},Rn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF3","NKF3"]);if(!n)return d("ekf",e.thresholds);let r=D(e,n),s=["IVN","IVE","IVD","IVT","IPN","IPE","IPD"].filter((a)=>r.has(a));if(s.length===0)return d("ekf",e.thresholds,`${n} has no IVN/IVE/IVD/IVT/IPN/IPE/IPD columns`);let i=t?.max_ratio??0.5,o=-1/0;for(let a of s){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM ${I(n)}`);if(c!==null&&c>o)o=c}if(o===-1/0)o=0;return A({check:"ekf",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak innovation ${o} (${n}: ${s.join("/")})`})},Mn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("min_cell_voltage",e.thresholds);if(!C(e,"BAT","Volt"))return d("min_cell_voltage",e.thresholds,"BAT missing Volt column");let n=t?.min_cell_v??3.3,r=_(e,'SELECT MAX("Volt") FROM "BAT"'),s=_(e,'SELECT MIN("Volt") FROM "BAT"');if(r===null||s===null||r<=0)return d("min_cell_voltage",e.thresholds,"BAT.Volt has no usable values");let i=Math.max(1,Math.round(r/4.2)),o=s/i;return A({check:"min_cell_voltage",thresholds:e.thresholds,failed:o<n,failSeverity:"CRITICAL",value:o,threshold_used:n,source:t?.source,detail:`${i}S pack (MAX pack ${r.toFixed(2)}V), min cell ${o.toFixed(3)}V vs floor ${n}V`})},In=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("voltage_sag",e.thresholds);if(!C(e,"BAT","VoltR")||!C(e,"BAT","Volt"))return d("voltage_sag",e.thresholds,"BAT missing VoltR/Volt columns");let n=t?.max_sag_v??2,r=_(e,'SELECT MAX("VoltR"-"Volt") FROM "BAT"');return A({check:"voltage_sag",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak sag ${(r??0).toFixed(2)}V (VoltR-Volt) vs ${n}V`})},Fn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("over_current",e.thresholds);if(!C(e,"BAT","Curr"))return d("over_current",e.thresholds,"BAT missing Curr column");let n=t?.max_current_a??200,r=_(e,'SELECT MAX("Curr") FROM "BAT"');return A({check:"over_current",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak current ${(r??0).toFixed(1)}A vs ${n}A`})},Pn=(e)=>{let t=e.thresholds.battery;if(!e.hasTable("BAT"))return d("internal_resistance",e.thresholds);if(!C(e,"BAT","Res"))return d("internal_resistance",e.thresholds,"BAT missing Res column");let n=_(e,'SELECT MAX("Res") FROM "BAT"');if(n===null||n===0)return d("internal_resistance",e.thresholds,"BAT.Res all zero/absent (not reported)");let r=t?.res_min_current_a??5,i=C(e,"BAT","Curr")?_(e,`SELECT MAX("Res") FROM "BAT" WHERE "Curr" >= ${r}`):n;if(i===null)return d("internal_resistance",e.thresholds,`no BAT samples at Curr \u2265 ${r} A \u2014 Res only valid under load (max raw ${n.toFixed(3)}\u03A9 is a low-current artifact)`);let o=t?.max_res_ohm??0.03;return A({check:"internal_resistance",thresholds:e.thresholds,failed:i>o,failSeverity:"HIGH",value:i,threshold_used:o,source:t?.source,detail:`peak internal resistance ${i.toFixed(4)}\u03A9 (at Curr \u2265 ${r} A) vs ${o}\u03A9`})},Dn=(e)=>{let t=e.thresholds.power;if(!e.hasTable("POWR"))return d("board_brownout",e.thresholds);if(!C(e,"POWR","Vcc"))return d("board_brownout",e.thresholds,"POWR missing Vcc column");let n=t?.min_vcc_v??4.5,r=_(e,'SELECT MIN("Vcc") FROM "POWR"');return A({check:"board_brownout",thresholds:e.thresholds,failed:r!==null&&r<n,failSeverity:"CRITICAL",value:r,threshold_used:n,source:t?.source,detail:`min board Vcc ${(r??0).toFixed(3)}V vs floor ${n}V`})},$n=(e)=>{let t=e.thresholds.rate;if(!e.hasTable("RATE"))return d("rate_tracking",e.thresholds);let n=D(e,"RATE"),s=[["RDes","R"],["PDes","P"],["YDes","Y"]].filter(([c,l])=>n.has(c)&&n.has(l));if(s.length===0)return d("rate_tracking",e.thresholds,"RATE has no RDes/R, PDes/P, YDes/Y pairs");let i=t?.max_err_dps??50,o=-1/0,a="";for(let[c,l]of s){let u=_(e,`SELECT MAX(ABS(${I(c)}-${I(l)})) FROM "RATE"`);if(u!==null&&u>o)o=u,a=c.replace("Des","")}if(o===-1/0)o=0;return A({check:"rate_tracking",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak rate-tracking error ${o.toFixed(2)} deg/s (axis ${a||"?"}) vs ${i} deg/s`})},On=(e)=>{let t=e.thresholds.gps;if(!e.hasTable("GPA"))return d("gps_accuracy",e.thresholds);if(!C(e,"GPA","HAcc"))return d("gps_accuracy",e.thresholds,"GPA missing HAcc column");let n=t?.hacc_max_m??5,r=_(e,'SELECT MAX("HAcc") FROM "GPA"');return A({check:"gps_accuracy",thresholds:e.thresholds,failed:r!==null&&r>n,failSeverity:"HIGH",value:r,threshold_used:n,source:t?.source,detail:`peak horizontal accuracy ${(r??0).toFixed(2)}m vs ${n}m`})},xn=(e)=>{let t=e.thresholds.ekf,n=Ye(e,["XKF4","NKF4"]);if(!n)return d("ekf_variance",e.thresholds);let r=D(e,n),s=["SV","SP","SH","SM"].filter((u)=>r.has(u));if(s.length===0)return d("ekf_variance",e.thresholds,`${n} has no SV/SP/SH/SM columns`);let i=t?.max_variance??1,o=-1/0,a="";for(let u of s){let f=_(e,`SELECT MAX(${I(u)}) FROM ${I(n)}`);if(f!==null&&f>o)o=f,a=u}if(o===-1/0)o=0;let c=r.has("FS")?_(e,`SELECT MAX("FS") FROM ${I(n)}`):null,l=c!==null&&c>0?` | EKF failsafe set (FS MAX=${c})`:"";return A({check:"ekf_variance",thresholds:e.thresholds,failed:o>i,failSeverity:"HIGH",value:o,threshold_used:i,source:t?.source,detail:`peak EKF variance ${o.toFixed(3)} (${n}: ${a||s.join("/")}) vs ${i}${l}`})},Ln=(e)=>{let t=e.thresholds.mag;if(!e.hasTable("MAG"))return d("mag_offsets",e.thresholds);let n=D(e,"MAG"),r=["OfsX","OfsY","OfsZ"].filter((a)=>n.has(a));if(r.length===0)return d("mag_offsets",e.thresholds,"MAG has no OfsX/OfsY/OfsZ columns");let s=t?.max_offset??600,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(ABS(${I(a)})) FROM "MAG"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"mag_offsets",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak mag offset ${i.toFixed(0)} (${o||r.join("/")}) vs ${s}`})},Nn=(e)=>{let t=e.thresholds.esc;if(!e.hasTable("ESC"))return d("esc_health",e.thresholds);let n=D(e,"ESC"),r=["Temp","MotTemp"].filter((f)=>n.has(f));if(r.length===0&&!n.has("Err"))return d("esc_health",e.thresholds,"ESC has no Temp/MotTemp/Err columns");let s=t?.max_temp_c??90,i=-1/0,o="";for(let f of r){let p=_(e,`SELECT MAX(${I(f)}) FROM "ESC"`);if(p!==null&&p>i)i=p,o=f}if(i===-1/0)i=0;let a=n.has("Err")?_(e,'SELECT MAX("Err") FROM "ESC"')??0:0,c=r.length>0&&i>s,l=a>0,u=l?` | ESC Err MAX=${a}`:"";return A({check:"esc_health",thresholds:e.thresholds,failed:c||l,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`peak ESC temp ${i.toFixed(1)}\xB0C (${o||"n/a"}) vs ${s}\xB0C${u}`})},Hn=(e)=>{if(!X(e.vehicleType))return d("thrust_margin",e.thresholds,`n/a for ${e.vehicleType} (lift/T:W is a rotorcraft metric)`);if(!e.hasTable("MOTB"))return d("thrust_margin",e.thresholds);let t=D(e,"MOTB");if(!t.has("FailFlags")&&!(t.has("ThrOut")&&t.has("LiftMax")))return d("thrust_margin",e.thresholds,"MOTB missing FailFlags and ThrOut/LiftMax columns");let n=t.has("FailFlags")?_(e,'SELECT MAX("FailFlags") FROM "MOTB"')??0:0,r=null;if(t.has("ThrOut")&&t.has("LiftMax")){let a=_(e,'SELECT AVG("ThrOut") FROM "MOTB"'),c=_(e,'SELECT AVG("LiftMax") FROM "MOTB"');if(a!==null&&c!==null&&c>0)r=a/c}let s=r!==null&&r>0.5,i=n>0,o=`MOTB FailFlags MAX=${n}`+(r!==null?`, mean ThrOut/LiftMax ${r.toFixed(2)} (low-margin > 0.5)`:"")+(i?" \u2014 THRUST-LOSS flagged":s?" \u2014 low thrust margin":"");return A({check:"thrust_margin",thresholds:e.thresholds,failed:i||s,failSeverity:"HIGH",value:r,threshold_used:0.5,detail:o})},Vn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_health",e.thresholds);let n=D(e,"IMU"),r=["EG","EA"].filter((a)=>n.has(a));if(r.length===0)return d("imu_health",e.thresholds,"IMU has no EG/EA error-count columns");let s=t?.max_err??0,i=-1/0,o="";for(let a of r){let c=_(e,`SELECT MAX(${I(a)}) FROM "IMU"`);if(c!==null&&c>i)i=c,o=a}if(i===-1/0)i=0;return A({check:"imu_health",thresholds:e.thresholds,failed:i>s,failSeverity:"HIGH",value:i,threshold_used:s,source:t?.source,detail:`max IMU error count ${i} (${o||r.join("/")}) vs ${s}`})},Bn=(e)=>{let t=e.thresholds.imu;if(!e.hasTable("IMU"))return d("imu_consistency",e.thresholds);let n=D(e,"IMU");if(!n.has("I"))return d("imu_consistency",e.thresholds,"IMU has no instance column I");let r=["AccX","AccY","AccZ"].filter((b)=>n.has(b)),s=["GyrX","GyrY","GyrZ"].filter((b)=>n.has(b));if(r.length===0&&s.length===0)return d("imu_consistency",e.thresholds,"IMU has no Acc*/Gyr* columns");let i=[...r,...s].map((b)=>`AVG(${I(b)}) ${I(b)}`).join(", "),o=e.db.query(`SELECT "I" AS "I", ${i} FROM "IMU" GROUP BY "I"`).all();if(o.length<2)return d("imu_consistency",e.thresholds,`only ${o.length} IMU instance \u2014 nothing to cross-check`);let a=(b)=>{let w=o.map((E)=>Number(E[b])).filter((E)=>Number.isFinite(E));return w.length>=2?Math.max(...w)-Math.min(...w):0},c=0,l="";for(let b of r){let w=a(b);if(w>c)c=w,l=b}let u=0,f="";for(let b of s){let w=a(b);if(w>u)u=w,f=b}let p=t?.accel_consistency_max??0.7,g=t?.gyro_consistency_max??0.3,k=c>p,S=u>g,y=k||S,h=c/p>=u/g?c:u,m=c/p>=u/g?p:g,v=y?`INCONSISTENT \u2014 ${k?`accel ${l} spread ${c.toFixed(3)} m/s\xB2 > ${p}`:""}${k&&S?"; ":""}${S?`gyro ${f} spread ${u.toFixed(3)} rad/s > ${g}`:""}`:`IMUs consistent \u2014 max inter-instance bias spread: accel ${c.toFixed(3)} m/s\xB2 (<${p}), gyro ${u.toFixed(3)} rad/s (<${g}); relative differences between instances are within healthy tolerance`;return A({check:"imu_consistency",thresholds:e.thresholds,failed:y,failSeverity:"HIGH",value:h,threshold_used:m,source:{kind:"rule-of-thumb",ref:"IMU inconsistency tolerance (~ArduPilot arming limits)"},detail:v})},jn=(e)=>{if(!e.hasTable("ERR"))return d("err_events",e.thresholds);if(!C(e,"ERR","Subsys")||!C(e,"ERR","ECode"))return d("err_events",e.thresholds,"ERR present but Subsys/ECode columns absent");let t=e.thresholds.battery?.err_subsys??6,n=e.db.query(`SELECT "Subsys" AS subsys, "ECode" AS ecode, COUNT(*) AS n FROM "ERR" WHERE "ECode" <> 0 AND "Subsys" <> ${t} GROUP BY "Subsys", "ECode" ORDER BY "Subsys", "ECode"`).all(),r=0,s=[];for(let i of n)r+=Number(i.n),s.push(`Subsys=${i.subsys} ECode=${i.ecode} \xD7${i.n}`);return A({check:"err_events",thresholds:e.thresholds,failed:r>0,failSeverity:"HIGH",value:r,threshold_used:0,detail:r>0?`${r} non-battery ERR event(s): ${s.join(", ")}`:"no non-battery ERR events"})},Un,Gn=(e)=>{if(!e.hasTable("MODE"))return d("mode_changes",e.thresholds);if(!C(e,"MODE","ModeNum"))return d("mode_changes",e.thresholds,"MODE missing ModeNum column");let t=e.db.query('SELECT "ModeNum" AS modenum FROM "MODE"').all(),n=t.length,r=n>0?n-1:0,s=new Map,i=!1;for(let a of t){let c=Number(a.modenum);if(s.set(c,(s.get(c)??0)+1),Un.has(c))i=!0}let o=[...s.entries()].sort((a,c)=>a[0]-c[0]).map(([a,c])=>`Mode${a}\xD7${c}`).join(", ");return A({check:"mode_changes",thresholds:e.thresholds,failed:i,failSeverity:"HIGH",value:r,threshold_used:0,detail:`${r} mode change(s); timeline: ${o||"\u2014"}`+(i?" \u2014 emergency mode (RTL/LAND) entered":"")})},Xn=(e)=>{let t=e.thresholds.airspeed;if(!Ke(e.vehicleType))return d("airspeed",e.thresholds,`n/a for ${e.vehicleType} (no fixed-wing airspeed)`);if(!e.hasTable("ARSP"))return d("airspeed",e.thresholds,"no ARSP (airspeed) data");if(!C(e,"ARSP","Airspeed"))return d("airspeed",e.thresholds,"ARSP missing Airspeed column");let n=t?.stall_min_ms??8,r={kind:"rule-of-thumb",ref:"default stall floor"};if(e.hasTable("PARM")){let i=_(e,`SELECT "Value" FROM "PARM" WHERE "Name"='ARSPD_FBW_MIN' LIMIT 1`);if(i!==null&&i>0)n=i,r={kind:"datasheet",ref:"ARSPD_FBW_MIN"}}let s=_(e,'SELECT MIN("Airspeed") FROM "ARSP" WHERE "Airspeed" > 2');if(s===null)return d("airspeed",e.thresholds,"no airborne airspeed samples");return A({check:"airspeed",thresholds:e.thresholds,failed:s<n,failSeverity:"HIGH",value:s,threshold_used:n,source:r,detail:`min in-flight airspeed ${s.toFixed(1)} m/s vs stall floor ${n} m/s`})},qn;var Ze=M(()=>{Un=new Set([6,9]),qn=[{id:"battery",run:_n},{id:"min_cell_voltage",run:Mn},{id:"voltage_sag",run:In},{id:"over_current",run:Fn},{id:"internal_resistance",run:Pn},{id:"board_brownout",run:Dn},{id:"attitude",run:wn},{id:"rate_tracking",run:$n},{id:"altitude",run:vn},{id:"hover",run:En},{id:"rcou",run:An},{id:"rcin",run:kn},{id:"thrust_margin",run:Hn},{id:"vibration",run:Tn},{id:"imu_health",run:Vn},{id:"imu_consistency",run:Bn},{id:"mag",run:Cn},{id:"mag_offsets",run:Ln},{id:"gps_accuracy",run:On},{id:"ekf",run:Rn},{id:"ekf_variance",run:xn},{id:"esc_health",run:Nn},{id:"airspeed",run:Xn},{id:"err_events",run:jn},{id:"mode_changes",run:Gn}]});import{existsSync as Wn,readFileSync as Jn}from"fs";import{dirname as Kn,join as de}from"path";import{fileURLToPath as zn}from"url";function nt(e){if(e){let t=de(e,".hydron","apm-params.json"),n=tt(t);if(n&&n.size>0)return n}for(let t of Yn){let n=tt(t);if(n)return n}return new Map}function rt(e,t){return t.get(e.toUpperCase())}function tt(e){if(!Wn(e))return;try{let t=Jn(e,"utf8"),n=JSON.parse(t);if(!n||typeof n!=="object")return;let r=new Map;for(let[s,i]of Object.entries(n)){if(!s||s.startsWith("_")||typeof i!=="object"||i===null)continue;let o={name:s};if(typeof i.min==="number"&&Number.isFinite(i.min))o.min=i.min;if(typeof i.max==="number"&&Number.isFinite(i.max))o.max=i.max;if(typeof i.units==="string"&&i.units)o.units=i.units;r.set(s.toUpperCase(),o)}return r}catch{return}}var et,Yn;var st=M(()=>{et=Kn(zn(import.meta.url)),Yn=[de(et,"..","data","apm-params.json"),de(et,"..","..","data","apm-params.json")]});import{existsSync as Qn,readFileSync as Zn}from"fs";import{join as er}from"path";function it(){return{ruleset_version:"v1",safety:{ARMING_CHECK:{min:1},FS_THR_ENABLE:{min:1},FENCE_ENABLE:{min:1}},range:{INS_GYRO_FILTER:{min:5,max:80,severity:"HIGH"},ATC_RAT_RLL_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_PIT_P:{min:0,max:0.5,severity:"HIGH"},ATC_RAT_YAW_P:{min:0,max:1,severity:"HIGH"},MOT_SPIN_ARM:{min:0,max:0.2,severity:"HIGH"},MOT_SPIN_MIN:{min:0,max:0.3,severity:"HIGH"},RTL_ALT:{min:200,max:1e4,severity:"HIGH"},WPNAV_SPEED:{min:50,max:2000,severity:"HIGH"}}}}function tr(e){let t=it(),n=er(e,".hydron","param-rules.yaml");if(!Qn(n))return t;try{let r=Zn(n,"utf8");return nr(t,r)}catch{return t}}function nr(e,t){let n={ruleset_version:e.ruleset_version,safety:{...e.safety},range:{...e.range}},r=null;for(let s of t.split(/\r?\n/)){let o=s.replace(/#.*$/,"").trim();if(!o||o.startsWith("-"))continue;let a=/^ruleset_version\s*:\s*(.+)$/.exec(o);if(a){n.ruleset_version=a[1].trim().replace(/^["']|["']$/g,""),r=null;continue}if(/^safety\s*:\s*$/.test(o)){r="safety";continue}if(/^range\s*:\s*$/.test(o)){r="range";continue}let c=/^([A-Za-z0-9_]+)\s*:\s*\{(.+)\}\s*$/.exec(o);if(c&&r){let l=c[1],u=rr(c[2]);if(r==="safety"){let f=u.min;if(typeof f==="number")n.safety[l]={min:f}}else{let{min:f,max:p,severity:g}=u;if(typeof f==="number"&&typeof p==="number")n.range[l]={min:f,max:p,severity:g==="CRITICAL"?"CRITICAL":"HIGH"}}}}return n}function rr(e){let t={};for(let n of e.split(",")){let r=/^\s*([A-Za-z0-9_]+)\s*:\s*(.+?)\s*$/.exec(n);if(!r)continue;let s=r[1],i=r[2].replace(/^["']|["']$/g,""),o=Number(i);t[s]=Number.isFinite(o)&&i!==""?o:i}return t}function sr(e){let t=new Map;for(let n of e)t.set(n.name.toUpperCase(),n.value);return t}function L(e){return{check:e.check,severity:e.severity,value:e.value,threshold_used:e.threshold_used,ruleset_version:e.ruleset_version,verdict:e.verdict,tier:"system",source:e.source,detail:e.detail}}function ot(e,t={}){let n=t.configDir?tr(t.configDir):it(),r=t.ruleset_version??n.ruleset_version,s=sr(e),i=nt(t.configDir);return[...ir(s,n,r),...or(s,r),...cr(s,n,r,i),...lr(e,null)]}function ir(e,t,n){let r=[],s={kind:"rule-of-thumb"},i=e.get("ARMING_CHECK");if(i===void 0)r.push(N("param.safety.arming",n,"ARMING_CHECK absent"));else{let u=i!==0;r.push(L({check:"param.safety.arming",severity:u?"OK":"CRITICAL",value:i,threshold_used:t.safety.ARMING_CHECK?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"arming checks enabled":"ARMING_CHECK=0 \u2014 ALL pre-arm safety checks are disabled",source:s}))}let o=e.get("BATT_LOW_VOLT"),a=e.get("BATT_CRT_VOLT");if(o===void 0&&a===void 0)r.push(N("param.safety.battery_failsafe",n,"BATT_LOW_VOLT/BATT_CRT_VOLT absent"));else{let u=(o??0)===0&&(a??0)===0;r.push(L({check:"param.safety.battery_failsafe",severity:u?"CRITICAL":"OK",value:u?0:a??o??0,threshold_used:0,verdict:u?"FAIL":"PASS",ruleset_version:n,detail:u?"battery failsafe not configured (BATT_LOW_VOLT and BATT_CRT_VOLT both 0)":"battery failsafe configured",source:s}))}let c=e.get("FS_THR_ENABLE");if(c===void 0)r.push(N("param.safety.radio_failsafe",n,"FS_THR_ENABLE absent"));else{let u=c!==0;r.push(L({check:"param.safety.radio_failsafe",severity:u?"OK":"HIGH",value:c,threshold_used:t.safety.FS_THR_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"radio failsafe enabled":"FS_THR_ENABLE=0 \u2014 radio/throttle failsafe is OFF",source:s}))}let l=e.get("FENCE_ENABLE");if(l===void 0)r.push(N("param.safety.fence",n,"FENCE_ENABLE absent"));else{let u=l!==0;r.push(L({check:"param.safety.fence",severity:u?"OK":"HIGH",value:l,threshold_used:t.safety.FENCE_ENABLE?.min??1,verdict:u?"PASS":"FAIL",ruleset_version:n,detail:u?"geofence enabled":"FENCE_ENABLE=0 \u2014 geofence disabled (advisory)",source:s}))}return r}function or(e,t){let n=[],r={kind:"rule-of-thumb"},s=e.get("BATT_CRT_VOLT"),i=ar(e);if(s===void 0||s===0||i===null||i<=0)n.push(N("param.consistency.battery_cells",t,"BATT_CRT_VOLT and a cell-count source required"));else{let l=s/i,u=l>=3&&l<=3.7;n.push(L({check:"param.consistency.battery_cells",severity:u?"OK":"HIGH",value:fe(l,3),threshold_used:3,verdict:u?"PASS":"FAIL",ruleset_version:t,detail:u?`per-cell critical voltage ${fe(l,2)}V across ${i}S looks sane`:`per-cell critical voltage ${fe(l,2)}V (${i}S) outside [3.0,3.7] \u2014 cell count vs BATT_CRT_VOLT inconsistent`,source:r}))}let o=e.get("FRAME_CLASS"),a=e.get("FRAME_TYPE");if(o===void 0&&a===void 0)n.push(N("param.consistency.frame",t,"FRAME_CLASS/FRAME_TYPE absent"));else{let l=(o??0)!==0&&(a??0)!==0;n.push(L({check:"param.consistency.frame",severity:l?"OK":"HIGH",value:o??null,threshold_used:1,verdict:l?"PASS":"FAIL",ruleset_version:t,detail:l?`frame configured (CLASS=${o}, TYPE=${a})`:`frame not fully configured (CLASS=${o??"?"}, TYPE=${a??"?"}) \u2014 must be non-zero for a copter`,source:r}))}let c=e.get("INS_HNTCH_ENABLE");if(c===void 0)n.push(N("param.consistency.notch_filter",t,"INS_HNTCH_ENABLE absent"));else n.push(L({check:"param.consistency.notch_filter",severity:"OK",value:c,threshold_used:null,verdict:"PASS",ruleset_version:t,detail:c===0?"harmonic notch filter disabled (INS_HNTCH_ENABLE=0) \u2014 advisory; tune if vibration is high":"harmonic notch filter enabled",source:r}));return n}function ar(e){for(let n of["BATT_CELLS","BATT_N_CELLS","BATT_CELL_COUNT"]){let r=e.get(n);if(r!==void 0&&r>0)return Math.round(r)}let t=e.get("BATT_ARM_VOLT");if(t!==void 0&&t>0)return Math.round(t/3.6);return null}function cr(e,t,n,r){let s=[];for(let[i,o]of Object.entries(t.range)){let a=e.get(i.toUpperCase()),c=`param.range.${i}`;if(a===void 0){s.push(N(c,n,`${i} absent`));continue}let l=rt(i,r),u=l!==void 0&&(typeof l.min==="number"||typeof l.max==="number"),f=u&&typeof l.min==="number"?Math.max(o.min,l.min):o.min,p=u&&typeof l.max==="number"?Math.min(o.max,l.max):o.max,g=u&&typeof l.min==="number"?l.min:o.min,k=u&&typeof l.max==="number"?l.max:o.max,S=u?{kind:"datasheet",ref:"apm.pdef.xml"}:{kind:"tuned"},y=a>=f&&a<=p;s.push(L({check:c,severity:y?"OK":o.severity,value:a,threshold_used:y?k:a<f?g:k,verdict:y?"PASS":"FAIL",ruleset_version:n,detail:y?`${i}=${a} within [${g},${k}]${u?" (apm.pdef.xml)":""}`:`${i}=${a} outside [${g},${k}]${u?" (apm.pdef.xml)":""}`,source:S}))}return s}function lr(e,t){return[]}function N(e,t,n){return L({check:e,severity:"OK",value:null,threshold_used:null,verdict:"SKIP",ruleset_version:t,detail:n})}function fe(e,t){let n=10**t;return Math.round(e*n)/n}var at=M(()=>{st()});import{existsSync as ur,readFileSync as dr}from"fs";import{join as fr}from"path";function mr(){return{ruleset_version:"v1",vibration:{field:"VibeX|VibeY|VibeZ",max_ms2:30,source:{kind:"rule-of-thumb"}},clipping:{field:"Clip",max:0},battery:{err_subsys:6,err_ecode:1,min_cell_v:3.3,max_sag_v:2,max_current_a:200,max_res_ohm:0.03,res_min_current_a:5,source:{kind:"rule-of-thumb"}},attitude:{fields:"DesRoll-Roll,DesPitch-Pitch",max_deg:5,window_samples:10},altitude:{field:"DAlt-Alt",max_m:2},hover:{field:"ThH",band:[0.25,0.75]},ekf:{fields:"IVN,IVE,IVD",max_ratio:0.5,max_variance:1},mag:{field:"Health",min:1,late_align_s:30,max_offset:600},gps:{field:"NSats",min:6,hdop_max:2,hacc_max_m:5},power:{min_vcc_v:4.5,source:{kind:"rule-of-thumb"}},rate:{max_err_dps:50,source:{kind:"rule-of-thumb"}},esc:{max_temp_c:90,source:{kind:"rule-of-thumb"}},imu:{max_err:0,accel_consistency_max:0.7,gyro_consistency_max:0.3,source:{kind:"rule-of-thumb"}},airspeed:{stall_min_ms:8,source:{kind:"rule-of-thumb"}}}}function lt(e){let t=mr(),n=fr(e,".hydron","uav-thresholds.yaml");if(!ur(n))return t;try{let r=hr(dr(n,"utf8"));return ut(t,r)}catch{return t}}function ut(e,t){let n={...e};for(let[r,s]of Object.entries(t)){let i=n[r];if(s&&typeof s==="object"&&!Array.isArray(s)&&i&&typeof i==="object"&&!Array.isArray(i))n[r]=ut(i,s);else n[r]=s}return n}function ct(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let s=e[r];if(s==="'"&&!n)t=!t;else if(s==='"'&&!t)n=!n;else if(s==="#"&&!t&&!n)return e.slice(0,r)}return e}function dt(e,t){let n=[],r=0,s=!1,i=!1,o=0;for(let a=0;a<e.length;a++){let c=e[a];if(c==="'"&&!i)s=!s;else if(c==='"'&&!s)i=!i;else if(!s&&!i){if(c==="["||c==="{")r++;else if(c==="]"||c==="}")r--;else if(c===t&&r===0)n.push(e.slice(o,a)),o=a+1}}return n.push(e.slice(o)),n}function q(e){let t=e.trim();if(t==="")return"";if(/^-?\d+(\.\d+)?$/.test(t))return Number(t);if(t==="true")return!0;if(t==="false")return!1;if(t.startsWith("[")&&t.endsWith("]")){let n=t.slice(1,-1).trim();return n?dt(n,",").map(q):[]}if(t.startsWith("{")&&t.endsWith("}"))return ft(t);return t.replace(/^["']|["']$/g,"")}function ft(e){let t=e.trim().replace(/^\{/,"").replace(/\}$/,""),n={};for(let r of dt(t,",")){let s=r.indexOf(":");if(s<0)continue;let i=r.slice(0,s).trim().replace(/^["']|["']$/g,"");if(i)n[i]=q(r.slice(s+1))}return n}function hr(e){let t={},n=e.split(/\r?\n/),r=0;while(r<n.length){let s=ct(n[r]);if(r++,!s.trim()||/^\s/.test(s))continue;let i=/^([A-Za-z0-9_]+):\s*(.*)$/.exec(s);if(!i)continue;let o=i[1],a=i[2].trim();if(a.startsWith("{"))t[o]=ft(a);else if(a!=="")t[o]=q(a);else{let c={};while(r<n.length){let l=ct(n[r]);if(!l.trim()){r++;continue}if(!/^\s/.test(l))break;r++;let u=/^\s+([A-Za-z0-9_]+):\s*(.*)$/.exec(l);if(u&&u[2].trim()!=="")c[u[1]]=q(u[2])}t[o]=c}}return t}var mt=()=>{};function T(e,t){let n=t.toLowerCase();return e.columns.findIndex((r)=>r.toLowerCase()===n)}function x(e){if(typeof e==="number")return Number.isFinite(e)?e:null;if(typeof e==="bigint")return Number(e);if(typeof e==="string"){let t=Number(e);return Number.isFinite(t)?t:null}return null}function pr(e){if(typeof e==="bigint")return e;if(typeof e==="number"&&Number.isFinite(e))return BigInt(Math.trunc(e));if(typeof e==="string"&&/^-?\d+$/.test(e.trim()))try{return BigInt(e.trim())}catch{return null}return null}function H(e){if(e===null||e===void 0)return null;if(typeof e==="string")return e;return String(e)}function W(e){return`"${e.replace(/"/g,'""')}"`}function ge(e,t){try{return!!e.query("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ?").get(t)}catch{return!1}}function ye(e,t){try{let n=e.query(`PRAGMA table_info(${W(t)})`).all();return new Set(n.map((r)=>r.name))}catch{return new Set}}function J(e,t){try{let n=e.query(t).get();if(!n)return null;let r=Object.values(n)[0];if(r===null||r===void 0)return null;let s=typeof r==="bigint"?Number(r):Number(r);return Number.isFinite(s)?s:null}catch{return null}}function gr(e){for(let t of["ATT","GPS","VIBE","CTUN","IMU"])if(ge(e,t)&&ye(e,t).has("TimeUS")){let n=J(e,`SELECT COUNT(*) AS c FROM ${W(t)}`);if(n===null||n<=0)continue;let r=J(e,`SELECT (MAX("TimeUS") - MIN("TimeUS")) AS d FROM ${W(t)}`);if(r!==null)return r/1e6}return null}function yr(e){if(!ge(e,"VIBE"))return null;let t=ye(e,"VIBE"),n=["VibeX","VibeY","VibeZ"].filter((s)=>t.has(s));if(n.length===0)return null;let r=n.map((s)=>`SELECT MAX(${W(s)}) AS m FROM "VIBE"`).join(" UNION ALL ");return J(e,`SELECT MAX(m) AS m FROM (${r})`)}function br(e){if(!ge(e,"CTUN")||!ye(e,"CTUN").has("ThH"))return null;return J(e,'SELECT AVG("ThH") AS m FROM "CTUN"')}function me(e,t){let n=e.tables.PARM;if(!n)return null;let r=T(n,"Name"),s=T(n,"Value");if(r<0||s<0)return null;let i=t.toLowerCase();for(let o of n.rows)if(H(o[r])?.toLowerCase()===i)return x(o[s]);return null}function pe(e,t){let n=e.tables.MSG;if(!n)return null;let r=T(n,"Message")>=0?T(n,"Message"):T(n,"Msg");if(r<0)return null;for(let s of n.rows){let i=H(s[r]);if(i&&t.test(i))return i}return null}function vr(e){let t=e.tables.MSG;if(!t)return null;let n=T(t,"Message")>=0?T(t,"Message"):T(t,"Msg");if(n<0)return null;for(let r of t.rows){let s=H(r[n]),i=s&&wr.exec(s.trim());if(i){let[,o,a,c,l]=i;return{id:`${a}${c}${l}`.toUpperCase(),name:`${o}-${a.toUpperCase()}`}}}return null}function Er(e){let t=vr(e),n=me(e,"SYSID_THISMAV"),r,s;if(t)r=t.id,s=t.name;else if(n!==null)r=`sysid-${n}`,s=pe(e,/ArduCopter|ArduPlane|ArduPilot|board/i)??r;else{let a=pe(e,/ArduCopter|ArduPlane|ArduPilot|ChibiOS|board/i);r=a??"unknown",s=a??r}let i,o=me(e,"Q_ENABLE");if(o!==null&&o>=1)i="QuadPlane";else{let a=me(e,"FRAME_CLASS");if(a!==null)i=_r[a]??`class_${a}`}return{kind:"airframe",external_id:r,attrs:{name:s,frame:i}}}function Ar(e){let t=e.tables.GPS;if(!t)return null;let n=T(t,"GWk"),r=T(t,"GMS");if(n<0||r<0)return null;let s=315964800000,i=18000,o=null;for(let c of t.rows){let l=x(c[n]),u=x(c[r]);if(l===null||u===null||l<=0)continue;let f=s+l*7*24*3600*1000+u-i;if(o===null||f<o)o=f}if(o===null)return null;let a=new Date(o);return Number.isNaN(a.getTime())?null:a.toISOString()}function kr(e,t,n){let r=pe(e,/ArduCopter|ArduPlane|ArduPilot/);return{kind:"analysis",source_hash:n,logged_at:Ar(e),attrs:{firmware:r??null,duration_s:gr(t),pilot_id:null,rc_id:null}}}function Tr(e){let t=e.tables.PARM;if(!t)return[];let n=T(t,"Name"),r=T(t,"Value");if(n<0||r<0)return[];let s=T(t,"Default"),i=[];for(let o of t.rows){let a=H(o[n]);if(!a)continue;let c=x(o[r]);if(c===null)continue;let l={name:a,value:c};if(s>=0){let u=x(o[s]);l.default=u}i.push(l)}return i}function he(e,t){let n=T(e,"TimeUS");if(n<0)return 0n;return pr(t[n])??0n}function Sr(e){let t=[],n=e.tables.ERR;if(n){let i=T(n,"Subsys"),o=T(n,"ECode");for(let a of n.rows)t.push({at:he(n,a),type:"ERR",payload:{Subsys:i>=0?x(a[i]):null,ECode:o>=0?x(a[o]):null}})}let r=e.tables.MODE;if(r){let i=T(r,"TimeUS");for(let o of r.rows){let a={};r.columns.forEach((c,l)=>{if(l===i)return;a[c]=x(o[l])??H(o[l])}),t.push({at:he(r,o),type:"MODE",payload:a})}}let s=e.tables.MSG;if(s){let i=T(s,"Message")>=0?T(s,"Message"):T(s,"Msg");for(let o of s.rows)t.push({at:he(s,o),type:"MSG",payload:{text:i>=0?H(o[i]):null}})}return t}function Cr(e,t){let n=[],r=yr(t);if(r!==null)n.push({name:"vibe_peak",value:r,unit:"m/s/s"});let s=e.tables.ERR;if(s){let o=T(s,"Subsys"),a=T(s,"ECode");if(o>=0&&a>=0){let c=0;for(let l of s.rows)if(x(l[o])===6&&x(l[a])===1)c++;n.push({name:"failsafe_count",value:c})}}let i=br(t);if(i!==null)n.push({name:"hover_thr",value:i});return n}function ht(e,t,n){return{entity:Er(e),episode:kr(e,t,n.sourceHash),params:Tr(e),events:Sr(e),measurements:Cr(e,t)}}var _r,wr;var pt=M(()=>{_r={0:"Undefined",1:"Quad",2:"Hexa",3:"Octa",4:"OctaQuad",5:"Y6",6:"Heli",7:"Tri",8:"SingleCopter",9:"CoaxCopter",10:"BiCopter",11:"Heli_Dual",12:"DodecaHexa",13:"HeliQuad",14:"Deca",15:"Scripting"};wr=/^([A-Za-z][A-Za-z0-9_+\-]*)\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\s+([0-9A-Fa-f]{8})\b/});import{mkdir as Rr,readFile as be,writeFile as yt,readdir as bt,stat as Mr}from"fs/promises";import{dirname as Us,join as V}from"path";function _t(e,t,n){return V(e,".hydron","observations",t,K(n))}function K(e){return e.replace(/[^A-Za-z0-9._-]/g,"_")||"unknown"}function Ir(e,t){return typeof t==="bigint"?t.toString():t}function wt(e){if(Array.isArray(e.events))e.events=e.events.map((t)=>{let n=t.at,r;if(typeof n==="bigint")r=n;else if(typeof n==="string"&&/^-?\d+$/.test(n))r=BigInt(n);else if(typeof n==="number")r=BigInt(Math.trunc(n));else r=0n;return{...t,at:r}});return e}function Fr(e){let t=e.findings??[],n=t.filter((o)=>o.verdict==="FAIL").length,r=t.filter((o)=>o.severity==="CRITICAL"&&o.verdict==="FAIL").length,s="OK";for(let o of t)if(gt[o.severity]>gt[s])s=o.severity;let i=(o)=>e.measurements?.find((a)=>a.name===o)?.value??null;return{source_hash:e.episode.source_hash,logged_at:e.episode.logged_at,ruleset_version:e.ruleset_version,anomalies:n,critical:r,vibe_peak:i("vibe_peak"),failsafe_count:i("failsafe_count"),worst_severity:s,...e.tags&&e.tags.length>0?{tags:e.tags}:{}}}async function Pr(e){let t;try{t=await be(e,"utf8")}catch{return[]}let n=[];for(let r of t.split(`
|
|
5
|
+
`)){let s=r.trim();if(!s)continue;try{n.push(JSON.parse(s))}catch{}}return n}async function Dr(e,t){let n=V(e,"index.jsonl"),r=await Pr(n),s=Fr(t),i=r.filter((o)=>o.source_hash!==s.source_hash);i.push(s),await yt(n,i.map((o)=>JSON.stringify(o)).join(`
|
|
6
6
|
`)+`
|
|
7
|
-
`,"utf8")}async function
|
|
8
|
-
`),X=Z.rows.length>50?`
|
|
9
|
-
\u2026 ${Z.rows.length-50} more rows`:Z.truncated?`
|
|
10
|
-
(capped at ${o} rows)`:"";return`${$}
|
|
11
|
-
${J}${X}`}var o=1e4;var k$=M(()=>{WZ()});self.onmessage=async(Z)=>{let $=Z.data;try{let J;if($.op==="analyze"){let{analyzeFlight:X}=await Promise.resolve().then(() => (M$(),S$));J=await X($.binPath,$.opts)}else if($.op==="query"){let{runUavQuery:X}=await Promise.resolve().then(() => (k$(),y$));J=await X($.opts)}else throw Error("unknown worker op");self.postMessage({ok:!0,result:J})}catch(J){self.postMessage({ok:!1,error:J instanceof Error?J.message:String(J)})}};
|
|
7
|
+
`,"utf8")}async function vt(e,t){let n=_t(t.projectDir,t.workspace,e.entity.external_id);await Rr(n,{recursive:!0});let r=V(n,`${K(e.episode.source_hash)}.json`);return await yt(r,JSON.stringify(e,Ir,2),"utf8"),await Dr(n,e),r}async function Et(e){let t=_t(e.projectDir,e.workspace,e.sysid),n;try{n=await bt(t)}catch{return null}let r=`${K(e.excludeSourceHash)}.json`,s=n.filter((o)=>o.endsWith(".json")&&o!==r),i=null;for(let o of s){let a=V(t,o),c;try{let p=await be(a,"utf8");c=wt(JSON.parse(p))}catch{continue}let l=0;try{l=(await Mr(a)).mtimeMs}catch{}let u=c.episode?.logged_at?Date.parse(c.episode.logged_at):NaN,f=Number.isNaN(u)?-1/0:u;if(i===null||f>i.loggedAt||f===i.loggedAt&&l>i.mtime)i={doc:c,loggedAt:f,mtime:l}}return i?.doc??null}async function $r(e,t,n){let r=V(e,".hydron","observations",t),s=`${K(n)}.json`,i;try{i=await bt(r)}catch{return null}for(let o of i){let a=V(r,o,s),c;try{let l=await be(a,"utf8");c=wt(JSON.parse(l))}catch{continue}return{path:a,doc:c}}return null}async function At(e){let t=await $r(e.projectDir,e.workspace,e.flight_id);if(!t)return[];return(t.doc.findings??[]).filter((n)=>n.origin==="agent")}var gt;var kt=M(()=>{gt={OK:0,HIGH:1,CRITICAL:2}});function Or(e,t){let n=new Map;for(let s of e)n.set(s.name,s.value);let r=[];for(let s of t){let i=n.get(s.name);if(i===void 0)continue;if(i!==s.value)r.push({name:s.name,old:i,new:s.value})}return r}function xr(e,t){return Or(e.params??[],t.params??[])}function Lr(e,t){let n=new Map;for(let s of e.findings??[])if(s.tier==="system")n.set(s.check,s);let r=[];for(let s of t.findings??[]){if(s.tier!=="system")continue;let i=n.get(s.check);if(!i)continue;if(i.severity!==s.severity)r.push({check:s.check,old:i.severity,new:s.severity})}return r}function Tt(e,t){return{param_changes:xr(e,t),finding_changes:Lr(e,t)}}import{createHash as Nr}from"crypto";import{open as Ct,stat as Hr}from"fs/promises";import{resolve as Vr}from"path";async function Br(e){let t=await Ct(e,"r");try{let n=Buffer.alloc(2);return await t.read(n,0,2,0),n[0]===St[0]&&n[1]===St[1]}finally{await t.close()}}async function jr(e){let t=await Ct(e,"r");try{let n=Nr("sha256"),r=Buffer.alloc(1048576),s=0;for(;;){let{bytesRead:i}=await t.read(r,0,r.length,s);if(i===0)break;n.update(r.subarray(0,i)),s+=i}return n.digest("hex").slice(0,16)}finally{await t.close()}}function Ur(e){let t=e.filter((s)=>s.verdict==="FAIL").length,n=e.filter((s)=>s.severity==="CRITICAL"&&s.verdict==="FAIL").length,r=e.filter((s)=>s.verdict==="PASS").length;return{total:e.length,passed:r,anomalies:t,critical:n}}async function Rt(e,t){if(await Hr(e),!await Br(e))throw Error(`Not an ArduPilot DataFlash .bin (missing 0xA3 0x95 header): ${e}`);let n=await jr(e),r=lt(t.configDir??t.projectDir),{log:s,db:i,cleanup:o}=await j(e,n,{configDir:t.configDir??t.projectDir});try{let a=ht(s,i,{sourceHash:n});a.episode.attrs.source_path=Vr(e);let c=Je(s);a.episode.attrs.vehicle_type=c;let l=Qe(i,r,{vehicleType:c});l=[...l,...ot(a.params,{configDir:t.configDir??t.projectDir,ruleset_version:r.ruleset_version})];let u=await At({projectDir:t.projectDir,workspace:t.workspace,flight_id:n});l=[...l,...u];let f={schema_version:1,entity:a.entity,episode:a.episode,params:a.params,findings:l,events:a.events,measurements:a.measurements,ruleset_version:r.ruleset_version},p=await Et({projectDir:t.projectDir,workspace:t.workspace,sysid:a.entity.external_id,excludeSourceHash:n}),g=await vt(f,{projectDir:t.projectDir,workspace:t.workspace}),k={flight_id:n,vehicle_id:a.entity.external_id,metadata:{airframe:a.entity.attrs.name??a.entity.external_id,firmware:a.episode.attrs.firmware??null,duration_s:a.episode.attrs.duration_s??null},partial_decode:s.partial,decoded_until:s.decodedUntil,checks:l,summary:Ur(l),ruleset_version:r.ruleset_version};if(p){let{param_changes:S,finding_changes:y}=Tt(p,f);k.comparison={prior_flight_id:p.episode.source_hash,param_changes:S,finding_changes:y,narration:{claims:[]}}}return{report:k,doc:f,episodePath:g}}finally{o()}}var St;var Mt=M(()=>{ae();Ze();at();mt();pt();kt();St=[163,149]});import{readdir as Gr,readFile as Xr}from"fs/promises";import{join as It}from"path";async function qr(e,t,n){let r=It(e,".hydron","observations",t),s;try{s=await Gr(r)}catch{throw Error(`No observation store at ${r}. Run uav_analyze first.`)}for(let i of s){let o=It(r,i,`${n}.json`);try{let c=JSON.parse(await Xr(o,"utf8"))?.episode?.attrs?.source_path;if(typeof c==="string"&&c)return c;throw Error(`Episode ${n} has no source_path; re-run uav_analyze to record it.`)}catch(a){if(a.code==="ENOENT")continue;throw a}}throw Error(`flight_id ${n} not found in the observation store. Run uav_analyze first.`)}function Wr(e){let t=e.trim();t=t.replace(/^```(?:sql)?\s*/i,"").replace(/\s*```$/,"").trim();for(;;){let s=t;if(t=t.replace(/^--[^\n]*\n?/,"").replace(/^\/\*[\s\S]*?\*\//,"").trimStart(),t===s)break}if(t=t.replace(/;\s*$/,""),t.includes(";"))throw Error("Only a single statement is allowed (no ';').");let n=t.replace(/^\(+\s*/,"");if(!(/^\s*(select|with|values)\b/i.test(n)||/^\s*explain\b/i.test(t)||/^\s*pragma\s+(table_info|table_list|table_xinfo|index_list|index_info|index_xinfo|database_list|collation_list|function_list|pragma_list)\b/i.test(t)))throw Error("uav_query is read-only: use SELECT/WITH/VALUES (comments & ```fences ok), EXPLAIN, or a read PRAGMA (table_info/table_list/index_*). For heavier analysis use Python via bash, not SQL.");if(/\b(insert|update|delete|drop|create|alter|attach|detach|replace|reindex|vacuum)\b/i.test(t))throw Error("Write/DDL keyword detected \u2014 uav_query is read-only.");if(!/\blimit\b/i.test(t))t+=` LIMIT ${_e}`;return t}async function Ft(e){let t=Wr(e.query),n=await qr(e.projectDir,e.workspace,e.flight_id),{db:r,cleanup:s}=await j(n,e.flight_id);try{r.exec?.("PRAGMA query_only = ON");let o=r.query(t).all(),a=o.length?Object.keys(o[0]):[],l=o.slice(0,_e).map((u)=>a.map((f)=>u[f]));return{columns:a,rows:l,truncated:o.length>_e}}finally{s()}}var _e=1e4;var Pt=M(()=>{ae()});self.onmessage=async(e)=>{let t=e.data;try{let n;if(t.op==="analyze"){await Promise.resolve().then(() => Mt());n=await Rt(t.binPath,t.opts)}else if(t.op==="query"){await Promise.resolve().then(() => Pt());n=await Ft(t.opts)}else throw Error("unknown worker op");self.postMessage({ok:!0,result:n})}catch(n){self.postMessage({ok:!1,error:n instanceof Error?n.message:String(n)})}};
|
package/skills/uav/SKILL.md
CHANGED
|
@@ -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;
|
|
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,
|
|
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
|
|
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.
|