@testrelic/maestro-analytics 1.3.0 → 1.3.1-next.81

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/dist/index.d.cts CHANGED
@@ -389,6 +389,9 @@ declare function printConsoleSummary(summary: Summary, outputPath: string, htmlR
389
389
 
390
390
  /**
391
391
  * Open a file path in the user's default browser.
392
+ *
393
+ * Uses `execFile` with an argv array (no shell) so a report path containing
394
+ * shell metacharacters can never be interpreted as a command.
392
395
  */
393
396
  declare function openInBrowser(filePath: string): void;
394
397
 
package/dist/index.d.ts CHANGED
@@ -389,6 +389,9 @@ declare function printConsoleSummary(summary: Summary, outputPath: string, htmlR
389
389
 
390
390
  /**
391
391
  * Open a file path in the user's default browser.
392
+ *
393
+ * Uses `execFile` with an argv array (no shell) so a report path containing
394
+ * shell metacharacters can never be interpreted as a command.
392
395
  */
393
396
  declare function openInBrowser(filePath: string): void;
394
397
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import {isValidEndpointUrl,isValidCloudConfig,createError,ErrorCode,isValidQueueEntry}from'@testrelic/core';import {existsSync,statSync,readFileSync,readdirSync,mkdirSync,writeFileSync,renameSync,unlinkSync,createReadStream}from'fs';import {resolve,join,dirname,basename,extname}from'path';import {XMLParser}from'fast-xml-parser';import {parseDocument}from'yaml';import {exec,spawn,execSync,spawnSync}from'child_process';import {tmpdir}from'os';import {createHash,randomUUID,randomBytes}from'crypto';import {fileURLToPath}from'url';import {gzipSync}from'zlib';import {Readable}from'stream';var bt=".testrelic",Lr="testrelic-config.json",Dr=".testrelic",Nr=5,Or=new Set(["__proto__","constructor","prototype"]),me=Object.freeze({apiKey:null,endpoint:"https://platform.testrelic.ai/api/v1",uploadStrategy:"batch",timeout:3e4,projectName:null,queueMaxAge:6048e5,queueDirectory:`${bt}/queue`,uploadArtifacts:true,artifactMaxSizeMb:50}),Ur={s:1e3,m:60*1e3,h:3600*1e3,d:1440*60*1e3};function ye(e){let t=resolve(e);for(let r=0;r<=Nr;r++){let n=join(t,bt,Lr);if(existsSync(n))try{if(statSync(n).isFile())return n}catch{}let o=join(t,Dr);if(existsSync(o))try{if(statSync(o).isFile())return process.stderr.write(`[testrelic] Deprecation: config file ".testrelic" has moved to ".testrelic/testrelic-config.json". Please migrate your config file to the new location.
2
- `),o}catch{}let s=dirname(t);if(s===t)break;t=s;}return null}function be(e){try{let t=readFileSync(e,"utf-8"),r=JSON.parse(t);return typeof r!="object"||r===null||Array.isArray(r)||!xt(r)?null:r}catch{return null}}function xt(e){for(let t of Object.keys(e)){if(Or.has(t))return false;let r=e[t];if(typeof r=="object"&&r!==null&&!Array.isArray(r)&&!xt(r))return false}return true}function K(e){let t=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(e);if(t)return process.env[t[1]]??null;let r=/^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(e);return r?process.env[r[1]]??null:e}function Y(e){let t=Object.create(null);for(let r of Object.keys(e)){let n=e[r];typeof n=="string"&&n.startsWith("$")?t[r]=K(n):typeof n=="object"&&n!==null&&!Array.isArray(n)?t[r]=Y(n):t[r]=n;}return t}function he(e){let t=/^(\d+)\s*([smhd])$/.exec(e.trim());if(!t)return null;let r=parseInt(t[1],10),n=t[2],o=Ur[n];return !o||r<=0?null:r*o}function xe(e,t){let r=Object.create(null);if(Object.assign(r,me),e){let l=e.cloud;l&&typeof l=="object"&&(typeof l.endpoint=="string"&&(r.endpoint=l.endpoint),typeof l.upload=="string"&&(r.uploadStrategy=l.upload),typeof l.timeout=="number"&&(r.timeout=l.timeout),typeof l.apiKey=="string"&&l.apiKey.length>0&&(r.apiKey=l.apiKey));let c=e["testrelic-repo"]??e.project;c&&typeof c=="object"&&typeof c.name=="string"&&(r.projectName=c.name);let d=e.queue;if(d&&typeof d=="object"){if(typeof d.maxAge=="string"){let u=he(d.maxAge);u!==null&&(r.queueMaxAge=u);}typeof d.directory=="string"&&(r.queueDirectory=d.directory);}}if(t){if(typeof t.apiKey=="string"&&t.apiKey.length>0){let l=t.apiKey.startsWith("$")?K(t.apiKey):t.apiKey;l&&(r.apiKey=l);}if(typeof t.endpoint=="string"){let l=t.endpoint.startsWith("$")?K(t.endpoint):t.endpoint;l&&(r.endpoint=l);}if(typeof t.upload=="string"&&(r.uploadStrategy=t.upload),typeof t.timeout=="number"&&(r.timeout=t.timeout),typeof t.projectName=="string"&&(r.projectName=t.projectName),typeof t.queueMaxAge=="string"){let l=he(t.queueMaxAge);l!==null&&(r.queueMaxAge=l);}typeof t.queueDirectory=="string"&&(r.queueDirectory=t.queueDirectory),typeof t.uploadArtifacts=="boolean"&&(r.uploadArtifacts=t.uploadArtifacts),typeof t.artifactMaxSizeMb=="number"&&(r.artifactMaxSizeMb=t.artifactMaxSizeMb);}let n=process.env.TESTRELIC_API_KEY;n&&n.length>0&&(r.apiKey=n);let o=process.env.TESTRELIC_CLOUD_ENDPOINT;o&&isValidEndpointUrl(o)&&(r.endpoint=o);let s=process.env.TESTRELIC_UPLOAD_STRATEGY;s&&["batch","realtime","both"].includes(s)&&(r.uploadStrategy=s);let i=process.env.TESTRELIC_CLOUD_TIMEOUT;if(i){let l=parseInt(i,10);!isNaN(l)&&l>=1e3&&l<=12e4&&(r.timeout=l);}let a=Object.freeze(r);return isValidCloudConfig(a)?a:me}var Br=["authorization","cookie","set-cookie","x-api-key"],jr=["password","secret","token","apiKey","api_key"],zr=1024*1024;function qr(e){let t=e??{},r=process.env.TESTRELIC_CAPTURE_NETWORK==="1"||process.env.TESTRELIC_CAPTURE_NETWORK?.toLowerCase()==="true";return Object.freeze({enabled:t.enabled??r??false,proxyPort:t.proxyPort??(process.env.TESTRELIC_PROXY_PORT?Number.parseInt(process.env.TESTRELIC_PROXY_PORT,10):8080),proxyHost:t.proxyHost??process.env.TESTRELIC_PROXY_HOST??"127.0.0.1",harPath:t.harPath??process.env.TESTRELIC_HAR_PATH??null,outputDir:t.outputDir??null,skipCertInstall:t.skipCertInstall??false,includeUrls:Object.freeze(t.includeUrls?[...t.includeUrls]:[]),excludeUrls:Object.freeze(t.excludeUrls?[...t.excludeUrls]:[]),redactHeaders:Object.freeze(t.redactHeaders?[...t.redactHeaders]:[...Br]),redactBodyFields:Object.freeze(t.redactBodyFields?[...t.redactBodyFields]:[...jr]),maxBodyBytes:t.maxBodyBytes??zr})}var Gr=new Set(["__proto__","constructor","prototype"]);function wt(e){if(typeof e!="object"||e===null)return false;for(let t of Object.keys(e))if(Gr.has(t))return true;return false}function Vr(e){if(typeof e!="object"||e===null||wt(e))return false;let t=e;return !(t.outputPath!==void 0&&typeof t.outputPath!="string"||t.htmlReportPath!==void 0&&typeof t.htmlReportPath!="string"||t.openReport!==void 0&&typeof t.openReport!="boolean"||t.includeScreenshots!==void 0&&typeof t.includeScreenshots!="boolean"||t.includeVideo!==void 0&&typeof t.includeVideo!="boolean"||t.includeAiAnalysis!==void 0&&typeof t.includeAiAnalysis!="boolean"||t.includeLogs!==void 0&&typeof t.includeLogs!="boolean"||t.includeFlowMetadata!==void 0&&typeof t.includeFlowMetadata!="boolean"||t.quiet!==void 0&&typeof t.quiet!="boolean"||t.metadata!==void 0&&t.metadata!==null&&(typeof t.metadata!="object"||wt(t.metadata)))}function Jr(e){if(e!==void 0&&!Vr(e))throw createError(ErrorCode.CONFIG_INVALID,"Invalid Maestro reporter configuration");let t=Object.create(null),r=e?.outputPath??"./test-results/testrelic-maestro.json";return t.outputPath=r,t.htmlReportPath=e?.htmlReportPath??r.replace(/\.json$/,".html"),t.openReport=e?.openReport??true,t.includeScreenshots=e?.includeScreenshots??true,t.includeVideo=e?.includeVideo??true,t.includeAiAnalysis=e?.includeAiAnalysis??true,t.includeLogs=e?.includeLogs??true,t.includeFlowMetadata=e?.includeFlowMetadata??true,t.flowsDir=e?.flowsDir??null,t.testRunId=e?.testRunId??null,t.metadata=e?.metadata??null,t.quiet=e?.quiet??false,t.reportMode=e?.reportMode??"batch",t.cloud=Wr(e?.cloud??null),t.network=qr(e?.network),Object.freeze(t)}function Wr(e){let t=ye(process.cwd()),r=t?be(t):null,n=r?Y(r):null,o=xe(n,e??void 0);return o.apiKey?o:null}var Xr=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",allowBooleanAttributes:true,parseAttributeValue:true,trimValues:true});function X(e){return e==null?[]:Array.isArray(e)?e:[e]}function kt(e){return !e||typeof e!="object"?[]:X(e.property).map(n=>({name:String(n["@_name"]??""),value:String(n["@_value"]??"")}))}function Qr(e){let t=String(e["@_name"]??"unnamed"),r=String(e["@_classname"]??t),n=Number(e["@_time"]??0),o=e["@_id"]!=null?String(e["@_id"]):null,s=String(e["@_status"]??"").toUpperCase(),i=e.failure,a=e.error,l=e.skipped!==void 0,c="SUCCESS";return i?c="FAILURE":a?c="ERROR":l?c="SKIPPED":s==="FAILURE"||s==="FAILED"?c="FAILURE":s==="ERROR"?c="ERROR":s==="SKIPPED"&&(c="SKIPPED"),{id:o,name:t,classname:r,time:n,status:c,failureMessage:i?String(i["@_message"]??i["#text"]??""):null,failureType:i?String(i["@_type"]??""):null,errorMessage:a?String(a["@_message"]??a["#text"]??""):null,errorType:a?String(a["@_type"]??""):null,properties:kt(e.properties)}}function vt(e){let t=String(e["@_name"]??"Test Suite"),r=e["@_device"]!=null?String(e["@_device"]):null,n=Number(e["@_tests"]??0),o=Number(e["@_failures"]??0),s=Number(e["@_errors"]??0),i=Number(e["@_skipped"]??0),a=Number(e["@_time"]??0),c=X(e.testcase).map(Qr);return {name:t,device:r,tests:n,failures:o,errors:s,skipped:i,time:a,testCases:c,properties:kt(e.properties)}}function Ct(e){let t=Xr.parse(e),r=[];if(t.testsuites){let l=t.testsuites;r=X(l.testsuite).map(vt);}else t.testsuite&&(r=X(t.testsuite).map(vt));let n=0,o=0,s=0,i=0,a=0;for(let l of r)n+=l.tests,o+=l.failures,s+=l.errors,i+=l.skipped,a+=l.time;return {testSuites:r,totalTests:n,totalFailures:o,totalErrors:s,totalSkipped:i,totalTime:a}}function we(e){let t=readFileSync(e,"utf-8");return Ct(t)}var on=new Set(["tapOn","doubleTapOn","longPressOn","inputText","eraseText","pasteText","swipe","scroll","scrollUntilVisible","hideKeyboard","pressKey","setClipboard","copyTextFrom"]),sn=new Set(["assertVisible","assertNotVisible","assertTrue","assertScreenshot","assertNoDefectsWithAI","assertWithAI","assertCondition"]),an=new Set(["launchApp","killApp","stopApp","clearState","openLink","back","clearKeychain"]),ln=new Set(["setAirplaneMode","toggleAirplaneMode","setLocation","setOrientation","setPermissions","addMedia","travel"]),cn=new Set(["takeScreenshot","startRecording","stopRecording"]),dn=new Set(["runScript","evalScript"]),un=new Set(["runFlow","repeat","retry","waitForAnimationToEnd","extendedWaitUntil"]),pn=new Set(["assertWithAI","assertNoDefectsWithAI","extractTextWithAI"]),fn=new Set(["inputText","pasteText"]),gn=200,mn=400;function Mt(e){return pn.has(e)?"ai":sn.has(e)?"assertion":on.has(e)?"interaction":an.has(e)?"navigation":ln.has(e)?"device":cn.has(e)?"media":dn.has(e)?"script":un.has(e)?"flow_control":"other"}var hn={tapOnElement:"tapOn",assertCondition:"assertVisible",backPress:"back",applyConfiguration:"applyConfiguration",defineVariables:"defineVariables"};function Rt(e){let t=e.replace(/Command$/,"");return hn[t]??t}var yn=new Set(["metadata","command","commandName","name","status","duration","durationMs","timestamp","time","error","errorMessage","selector","commands","subSteps","children","sequenceNumber"]);function bn(e){for(let t of Object.keys(e)){if(yn.has(t))continue;let r=e[t];if(r&&typeof r=="object"&&!Array.isArray(r))return t}}function St(e){if(e.selector&&typeof e.selector=="object"){let t=e.selector;if(typeof t.textRegex=="string")return t.textRegex;if(typeof t.text=="string")return t.text;if(typeof t.id=="string")return `#${t.id}`}if(e.condition&&typeof e.condition=="object"){let t=e.condition,r=t.visible??t.notVisible;if(r){if(typeof r.textRegex=="string")return r.textRegex;if(typeof r.text=="string")return r.text}}if(typeof e.path=="string")return e.path}function Tt(e,t){return e.length<=t?e:`${e.slice(0,t)}\u2026`}function xn(e){return e.length===0?"":`[REDACTED ${e.length} chars]`}function At(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.x=="number"&&typeof t.y=="number")return `${t.x},${t.y}`}function It(e,t){let r={};switch(e){case "inputText":case "pasteText":{let n=t.text??t.value;typeof n=="string"&&(r.text=fn.has(e)?xn(n):n);break}case "swipe":case "scroll":case "scrollUntilVisible":{typeof t.direction=="string"&&(r.direction=t.direction);let n=At(t.start??t.startRelative),o=At(t.end??t.endRelative);n&&(r.start=n),o&&(r.end=o),typeof t.duration=="number"&&(r.swipeDurationMs=t.duration),typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "setLocation":{typeof t.latitude=="number"&&(r.latitude=t.latitude),typeof t.longitude=="number"&&(r.longitude=t.longitude);break}case "pressKey":case "back":{typeof t.key=="string"?r.key=t.key:typeof t.code=="string"&&(r.key=t.code);break}case "setOrientation":{typeof t.orientation=="string"&&(r.orientation=t.orientation);break}case "setAirplaneMode":case "toggleAirplaneMode":{(typeof t.value=="string"||typeof t.value=="boolean")&&(r.value=t.value);break}case "setPermissions":{t.permissions&&typeof t.permissions=="object"&&(r.permissions=t.permissions);break}case "addMedia":{Array.isArray(t.mediaPaths)?r.mediaPaths=t.mediaPaths:typeof t.path=="string"&&(r.mediaPaths=[t.path]);break}case "launchApp":case "killApp":case "stopApp":case "clearState":{let n=t.appId??t.packageName??t.bundleId;typeof n=="string"&&(r.appId=n),t.arguments&&(r.arguments=t.arguments);break}case "openLink":{typeof t.url=="string"?r.url=t.url:typeof t.link=="string"&&(r.url=t.link);break}case "runScript":case "evalScript":{typeof t.path=="string"&&(r.path=t.path);let n=t.script??t.scriptString;typeof n=="string"&&(r.script=Tt(n,gn)),typeof t.sourceDescription=="string"&&(r.sourceDescription=t.sourceDescription);break}case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":{let n=t.assertion??t.prompt??t.question;typeof n=="string"&&(r.prompt=Tt(n,mn));break}case "extendedWaitUntil":case "waitForAnimationToEnd":{typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "repeat":case "retry":{typeof t.times=="number"&&(r.times=t.times),typeof t.maxRetries=="number"&&(r.maxRetries=t.maxRetries),typeof t.condition=="object"&&t.condition&&(r.condition=t.condition);break}case "runFlow":{typeof t.file=="string"&&(r.file=t.file),typeof t.flowId=="string"&&(r.flowId=t.flowId);break}default:for(let n of ["text","value","url"]){let o=t[n];if(typeof o=="string"||typeof o=="number"||typeof o=="boolean"){r[n]=o;break}}}return Object.keys(r).length>0?r:void 0}function ve(e,t,r){let n=[e.commands,t.commands,t.subSteps,t.children];for(let o of n)if(Array.isArray(o)&&o.length>0)return o.map((s,i)=>ke(s,i,r));return []}function ke(e,t,r){let n,o,s,i=[];if(typeof e.command=="object"&&e.command!==null&&!Array.isArray(e.command)){let y=e.command,h=Object.keys(y)[0]??`step-${t}`;n=Rt(h);let g=y[h]??{};o=St(g),s=It(n,g),i=ve(g,e,r);}else {let y=bn(e);if(y){n=Rt(y);let h=e[y]??{};o=St(h),s=It(n,h),i=ve(h,e,r);}else n=e.command??e.commandName??e.name??`step-${t}`,o=e.selector??void 0,i=ve({},e,r);}let a=e.metadata??{},l=wn(a.status??e.status),c=a.duration??e.duration??e.durationMs??0,d=typeof a.sequenceNumber=="number"?a.sequenceNumber:void 0,u;typeof a.timestamp=="number"?u=new Date(a.timestamp).toISOString():u=e.timestamp??e.time??r;let p=e.error??e.errorMessage??void 0;return {command:n,category:Mt(n),status:l,duration:c,timestamp:u,...o?{selector:o}:{},...p?{error:p}:{},...s?{details:s}:{},...d!==void 0?{sequenceNumber:d}:{},...i.length>0?{children:i}:{}}}function wn(e){if(!e)return "completed";let t=e.toLowerCase();return t==="failed"||t==="error"?"failed":t==="skipped"?"skipped":"completed"}function Et(e,t){let r=t??new Date().toISOString();try{let n=JSON.parse(e);if(Array.isArray(n))return n.map((o,s)=>ke(o,s,r));if(typeof n=="object"&&n!==null){let o=n,s=o.commands??o.steps??o.data;if(Array.isArray(s))return s.map((i,a)=>ke(i,a,r))}return []}catch{return []}}function Ce(e,t){try{let r=readFileSync(e,"utf-8");return Et(r,t)}catch{return []}}function Re(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t).startsWith("commands")&&t.endsWith(".json")).map(t=>join(e,t))}catch{return []}}function Tn(e){let t=[];for(let r of e)if(typeof r=="object"&&r!==null){let n=r;if(typeof n.runFlow=="string")t.push(n.runFlow);else if(typeof n.runFlow=="object"&&n.runFlow!==null){let o=n.runFlow;typeof o.file=="string"&&t.push(o.file);}}return t}function Pt(e){if(!e)return [];let t=[],r=Array.isArray(e)?e:[e];for(let n of r)if(typeof n=="string")t.push(n);else if(typeof n=="object"&&n!==null){let o=n;if(typeof o.runFlow=="string")t.push(o.runFlow);else if(typeof o.runFlow=="object"&&o.runFlow!==null){let s=o.runFlow;typeof s.file=="string"&&t.push(s.file);}typeof o.runScript=="string"&&t.push(o.runScript);}return t}function _t(e,t){let r=e.split(/^---\s*$/m,2),n=r[0]??"",o=r[1]??"",s={};try{let b=parseDocument(n).toJS();typeof b=="object"&&b!==null&&!Array.isArray(b)&&(s=b);}catch{}let i=[];if(o.trim())try{let b=parseDocument(o).toJS();Array.isArray(b)&&(i=b);}catch{}let a=typeof s.appId=="string"?s.appId:null,l=typeof s.name=="string"?s.name:null,c=[];if(Array.isArray(s.tags))for(let g of s.tags)typeof g=="string"&&c.push(g);let d={};if(typeof s.env=="object"&&s.env!==null&&!Array.isArray(s.env))for(let[g,b]of Object.entries(s.env))d[g]=String(b);let u={};if(typeof s.properties=="object"&&s.properties!==null&&!Array.isArray(s.properties))for(let[g,b]of Object.entries(s.properties))u[g]=String(b);let p=Pt(s.onFlowStart),y=Pt(s.onFlowComplete),h=Tn(i);return {appId:a,name:l,tags:c,env:d,properties:u,onFlowStart:p,onFlowComplete:y,subflowRefs:h,filePath:t}}function Se(e){let t=readFileSync(e,"utf-8");return _t(t,e)}function Te(e){if(!existsSync(e))return [];let t=[];function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);if(s.isDirectory())r(i);else if(s.isFile()){let a=extname(s.name).toLowerCase();(a===".yaml"||a===".yml")&&t.push(i);}}}catch{}}return r(e),t}var Pn=/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)\s+\[?\s*(\w+)\s*\]?\s+(.+)$/,_n=/^\[?(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]?\s+\[?\s*(\w+)\s*\]?\s+(.+)$/;function Lt(e){let t=e.toUpperCase();return t==="DEBUG"||t==="TRACE"||t==="VERBOSE"?"DEBUG":t==="INFO"?"INFO":t==="WARN"||t==="WARNING"?"WARN":t==="ERROR"||t==="FATAL"||t==="SEVERE"?"ERROR":"INFO"}function Ln(e,t){let r=/^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/.exec(t);if(!r)return new Date().toISOString();let n=Number(r[1]),o=Number(r[2]),s=Number(r[3]),i=r[4]?Number(r[4].padEnd(3,"0")):0;return new Date(e.getFullYear(),e.getMonth(),e.getDate(),n,o,s,i).toISOString()}function Dt(e,t){let r=[],n=e.split(`
3
- `),o=t instanceof Date?t:null,s=typeof t=="string"?t:t instanceof Date?`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`:new Date().toISOString().split("T")[0];for(let i of n){let a=i.trim();if(!a)continue;let l=Pn.exec(a);if(l){r.push({timestamp:l[1],level:Lt(l[2]),message:l[3],source:null});continue}if(l=_n.exec(a),l){let c=o?Ln(o,l[1]):`${s}T${l[1]}`;r.push({timestamp:c,level:Lt(l[2]),message:l[3],source:null});continue}if(r.length>0){let c=r[r.length-1];r[r.length-1]={...c,message:c.message+`
4
- `+a};}}return r}function Ae(e,t){try{let r=readFileSync(e,"utf-8");return Dt(r,t)}catch{return []}}function Ie(e){for(let t of e){let r=t.message.toLowerCase();if(r.includes("android")||r.includes("adb")||r.includes("uiautomator")||r.includes("emulator"))return "android";if(r.includes("ios")||r.includes("xcuitest")||r.includes("simulator")||r.includes("xctest"))return "ios";if(r.includes("web driver")||r.includes("chrome")||r.includes("chromium"))return "web"}return "unknown"}function Me(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t)==="maestro.log"||t.endsWith(".log")).map(t=>join(e,t))}catch{return []}}var Bn=/(?:defect|issue|bug|error|warning|problem)/i,jn=/(?:critical|severe|major|blocker)/i,zn=/(?:warning|moderate|minor)/i,Ee=/(?:cut[\s-]?off|overlap|truncat|misalign|overflow|clip|obscur|hidden\s+text|broken\s+layout)/i,Q=/(?:spelling|typo|misspell|grammar)/i,Z=/(?:i18n|internationali[sz]ation|locali[sz]ation|untranslated|missing\s+translation)/i,Le=/(?:layout|spacing|padding|margin|alignment|centering|position)/i,De=/(?:accessib|a11y|contrast|screen\s*reader|alt\s*text|aria)/i;function Fe(e){return Q.test(e)?"spelling":Z.test(e)?"i18n":De.test(e)?"accessibility":Le.test(e)?"layout":"ui"}function Pe(e){return jn.test(e)?"critical":zn.test(e)?"warning":"info"}function _e(e){return e.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim()}function qn(e){let t=[],r=_e(e),n=/<li[^>]*>([\s\S]*?)<\/li>/gi,o;for(;(o=n.exec(e))!==null;){let s=o[1],i=_e(s);!i||i.length<5||(Bn.test(i)||Ee.test(i)||Q.test(i)||Z.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}if(t.length===0){let s=/<p[^>]*>([\s\S]*?)<\/p>/gi;for(;(o=s.exec(e))!==null;){let i=_e(o[1]);!i||i.length<10||(Ee.test(i)||Q.test(i)||Z.test(i)||Le.test(i)||De.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}}if(t.length===0&&r.length>20){let s=r.split(/[.!?]+/).filter(i=>i.trim().length>10);for(let i of s){let a=i.trim();(Ee.test(a)||Q.test(a)||Z.test(a)||Le.test(a)||De.test(a))&&t.push({type:Fe(a),severity:Pe(a),description:a,location:null,screenshot:null});}}return t}function Nt(e){let t=qn(e);return {defects:t,totalDefects:t.length,hasIssues:t.length>0,rawHtml:e}}function Ne(e){try{let t=readFileSync(e,"utf-8");return Nt(t)}catch{return {defects:[],totalDefects:0,hasIssues:false,rawHtml:null}}}function Oe(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>{let r=basename(t).toLowerCase();return extname(t).toLowerCase()===".html"&&(r.includes("insight")||r.includes("ai")||r.includes("analysis"))}).map(t=>join(e,t))}catch{return []}}var Yn=new Set([".png",".jpg",".jpeg",".webp"]),Xn=new Set([".mp4",".webm",".mov"]);function Ot(e){let t=[];if(!existsSync(e))return t;function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);s.isDirectory()?r(i):s.isFile()&&t.push(i);}}catch{}}return r(e),t}function Ue(e,t){let r=[],n=[],o=[],s=[],i=[],a=null,l=[];e&&l.push(...Ot(e)),t&&l.push(...Ot(t));let c=new Set;for(let d of l){if(c.has(d))continue;c.add(d);let u=basename(d).toLowerCase(),p=extname(d).toLowerCase();if(Yn.has(p)){r.push(d);continue}if(Xn.has(p)){n.push(d);continue}if(u==="maestro.log"||p===".log"&&u.includes("maestro")){o.push(d);continue}if(u.startsWith("commands")&&p===".json"){s.push(d);continue}if(p===".html"&&(u.includes("insight")||u.includes("ai")||u.includes("analysis"))){i.push(d);continue}if(p===".xml"&&(u.includes("report")||u.includes("junit"))){a||(a=d);continue}}return {screenshotPaths:r,videoPaths:n,logPaths:o,commandJsonPaths:s,aiReportPaths:i,junitReportPath:a}}function Qn(e){return {screenshots:e.screenshotPaths.length,videos:e.videoPaths.length,logs:e.logPaths.length,commandFiles:e.commandJsonPaths.length,aiReports:e.aiReportPaths.length,junitReport:e.junitReportPath?1:0}}function Zn(e){switch(e){case "interaction":return "ui_action";case "assertion":return "assertion";case "ai":return "assertion";case "navigation":return "navigation";case "device":return "custom_step";case "media":return "custom_step";case "script":return "custom_step";case "flow_control":return "custom_step";case "recording":return "custom_step";default:return "custom_step"}}function eo(e){let t=e.details;if(t)switch(e.command){case "inputText":case "pasteText":if(typeof t.text=="string")return `${e.command} \u2192 ${t.text}`;break;case "swipe":case "scroll":case "scrollUntilVisible":if(typeof t.direction=="string")return `${e.command} ${t.direction}`;break;case "setLocation":if(typeof t.latitude=="number"&&typeof t.longitude=="number")return `setLocation ${t.latitude},${t.longitude}`;break;case "pressKey":if(typeof t.key=="string")return `pressKey ${t.key}`;break;case "setOrientation":if(typeof t.orientation=="string")return `setOrientation ${t.orientation}`;break;case "launchApp":case "killApp":case "stopApp":case "clearState":if(typeof t.appId=="string")return `${e.command} ${t.appId}`;break;case "openLink":if(typeof t.url=="string")return `openLink ${t.url}`;break;case "runScript":case "evalScript":if(typeof t.path=="string")return `${e.command} ${t.path}`;if(typeof t.sourceDescription=="string")return `${e.command} ${t.sourceDescription}`;if(typeof t.script=="string")return `${e.command} ${t.script}`;break;case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":if(typeof t.prompt=="string")return `${e.command} \u2192 ${t.prompt}`;break;case "retry":if(typeof t.maxRetries=="number")return `retry \xD7 ${t.maxRetries}`;break;case "repeat":if(typeof t.times=="number")return `repeat \xD7 ${t.times}`;break;case "runFlow":if(typeof t.file=="string")return `runFlow ${t.file}`;break}return e.selector?`${e.command} \u2192 ${e.selector}`:e.command}function He(e,t){let r=Date.parse(e.timestamp),n=Number.isFinite(r)&&Number.isFinite(t)?Math.max(0,(r-t)/1e3):null,o=(e.children??[]).map(s=>He(s,t));return {title:eo(e),category:Zn(e.category),status:e.status==="failed"?"failed":"passed",duration:e.duration,timestamp:e.timestamp,videoOffset:n,error:e.error??null,children:o}}function to(e,t){let r=Date.parse(e.timestamp),n=Date.parse(t.timestamp);return Number.isFinite(r)&&Number.isFinite(n)&&r!==n?r-n:0}function ro(e,t){let r=Date.parse(e.startedAt),n=[...e.commands].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),o=[...e.assertions].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),s=[...n.map(l=>He(l,r)),...o.map(l=>He(l,r))];s.sort(to);let i=e.screenshotPaths.length>0||e.videoPath?{screenshot:e.screenshotPaths[0]??void 0,video:e.videoPath??void 0}:null,a=[...e.tags];return e.platform!=="unknown"&&!a.includes(e.platform)&&a.push(e.platform),{title:e.flowName,status:e.status,duration:e.duration,startedAt:e.startedAt,completedAt:e.completedAt,retryCount:0,tags:a,failure:e.failureMessage?{message:e.failureMessage,line:null,code:null,stack:null}:null,testId:`${e.flowFile}::${e.flowName}`,filePath:e.flowFile,suiteName:e.appId??"maestro-suite",testType:"mobile",isFlaky:false,retryStatus:null,expectedStatus:"passed",actualStatus:e.status,artifacts:i,networkRequests:null,apiCalls:t.length>0?[...t]:null,apiAssertions:null,actions:s.length>0?s:null,consoleLogs:null}}function Ut(e,t){let r=`${e.flowFile}::${e.flowName}`,n=t?.get(r)??[],o=ro(e,n);return {url:e.appId??"maestro-flow",navigationType:"page_load",visitedAt:e.startedAt,duration:e.duration,specFile:e.flowFile,domContentLoadedAt:null,networkIdleAt:null,networkStats:null,tests:[o]}}function $e(e,t){return e.map(r=>Ut(r,t))}var Ht={"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0};function no(e){return e===null?"error":e>=200&&e<300?"2xx":e>=300&&e<400?"3xx":e>=400&&e<500?"4xx":e>=500&&e<600?"5xx":"error"}function Be(e,t){if(e.length===0)return null;let r=Math.min(e.length-1,Math.floor(t/100*e.length));return e[r]}function oo(e){if(e.length===0)return {totalApiCalls:0,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:{...Ht},apiResponseTime:null};let t={},r={...Ht},n=new Set,o=[];for(let i of e)t[i.method]=(t[i.method]??0)+1,r[no(i.responseStatusCode)]+=1,n.add(i.url),Number.isFinite(i.responseTimeMs)&&i.responseTimeMs>0&&o.push(i.responseTimeMs);o.sort((i,a)=>i-a);let s=o.length>0?{p50:Be(o,50)??0,p95:Be(o,95)??0,p99:Be(o,99)??0,avg:o.reduce((i,a)=>i+a,0)/o.length,min:o[0],max:o[o.length-1]}:null;return {totalApiCalls:e.length,uniqueApiUrls:n.size,apiCallsByMethod:t,apiCallsByStatusRange:r,apiResponseTime:s}}function G(e){let t=0,r=0,n=0,o=0,s=0,i=0,a=0,l=0,c=0,d=e.length,u=0,p={},y=new Set,h=[];for(let b of e){y.add(b.url);for(let x of b.tests){switch(t++,x.status){case "passed":r++;break;case "failed":n++;break;case "flaky":o++;break;case "skipped":s++;break;case "timedout":i++;break}if(x.actions)for(let T of x.actions)if(u++,T.category==="assertion")a++,T.status==="passed"?l++:c++;else {let R=T.category;p[R]=(p[R]??0)+1;}x.apiCalls&&x.apiCalls.length>0&&h.push(...x.apiCalls);}}let g=oo(h);return {total:t,passed:r,failed:n,flaky:o,skipped:s,timedout:i,...g,totalAssertions:a,passedAssertions:l,failedAssertions:c,totalNavigations:d,uniqueNavigationUrls:y.size,totalTimelineSteps:e.length,totalActionSteps:u,actionStepsByCategory:p}}var $t=`
1
+ import {isValidEndpointUrl,isValidCloudConfig,createError,ErrorCode,isValidQueueEntry}from'@testrelic/core';import {existsSync,statSync,readFileSync,readdirSync,mkdirSync,writeFileSync,renameSync,unlinkSync,createReadStream}from'fs';import {resolve,join,dirname,basename,extname}from'path';import {XMLParser}from'fast-xml-parser';import {parseDocument}from'yaml';import {execFile,spawn,execSync,spawnSync}from'child_process';import {tmpdir}from'os';import {createHash,randomUUID,randomBytes}from'crypto';import {fileURLToPath}from'url';import {gzipSync}from'zlib';import {Readable}from'stream';var bt=".testrelic",Dr="testrelic-config.json",Nr=".testrelic",Or=5,Ur=new Set(["__proto__","constructor","prototype"]),me=Object.freeze({apiKey:null,endpoint:"https://platform.testrelic.ai/api/v1",uploadStrategy:"batch",timeout:3e4,projectName:null,queueMaxAge:6048e5,queueDirectory:`${bt}/queue`,uploadArtifacts:true,artifactMaxSizeMb:50}),Hr={s:1e3,m:60*1e3,h:3600*1e3,d:1440*60*1e3};function ye(e){let t=resolve(e);for(let r=0;r<=Or;r++){let n=join(t,bt,Dr);if(existsSync(n))try{if(statSync(n).isFile())return n}catch{}let o=join(t,Nr);if(existsSync(o))try{if(statSync(o).isFile())return process.stderr.write(`[testrelic] Deprecation: config file ".testrelic" has moved to ".testrelic/testrelic-config.json". Please migrate your config file to the new location.
2
+ `),o}catch{}let s=dirname(t);if(s===t)break;t=s;}return null}function be(e){try{let t=readFileSync(e,"utf-8"),r=JSON.parse(t);return typeof r!="object"||r===null||Array.isArray(r)||!xt(r)?null:r}catch{return null}}function xt(e){for(let t of Object.keys(e)){if(Ur.has(t))return false;let r=e[t];if(typeof r=="object"&&r!==null&&!Array.isArray(r)&&!xt(r))return false}return true}function K(e){let t=/^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(e);if(t)return process.env[t[1]]??null;let r=/^\$([A-Za-z_][A-Za-z0-9_]*)$/.exec(e);return r?process.env[r[1]]??null:e}function Y(e){let t=Object.create(null);for(let r of Object.keys(e)){let n=e[r];typeof n=="string"&&n.startsWith("$")?t[r]=K(n):typeof n=="object"&&n!==null&&!Array.isArray(n)?t[r]=Y(n):t[r]=n;}return t}function he(e){let t=/^(\d+)\s*([smhd])$/.exec(e.trim());if(!t)return null;let r=parseInt(t[1],10),n=t[2],o=Hr[n];return !o||r<=0?null:r*o}function xe(e,t){let r=Object.create(null);if(Object.assign(r,me),e){let l=e.cloud;l&&typeof l=="object"&&(typeof l.endpoint=="string"&&(r.endpoint=l.endpoint),typeof l.upload=="string"&&(r.uploadStrategy=l.upload),typeof l.timeout=="number"&&(r.timeout=l.timeout),typeof l.apiKey=="string"&&l.apiKey.length>0&&(r.apiKey=l.apiKey));let c=e["testrelic-repo"]??e.project;c&&typeof c=="object"&&typeof c.name=="string"&&(r.projectName=c.name);let d=e.queue;if(d&&typeof d=="object"){if(typeof d.maxAge=="string"){let u=he(d.maxAge);u!==null&&(r.queueMaxAge=u);}typeof d.directory=="string"&&(r.queueDirectory=d.directory);}}if(t){if(typeof t.apiKey=="string"&&t.apiKey.length>0){let l=t.apiKey.startsWith("$")?K(t.apiKey):t.apiKey;l&&(r.apiKey=l);}if(typeof t.endpoint=="string"){let l=t.endpoint.startsWith("$")?K(t.endpoint):t.endpoint;l&&(r.endpoint=l);}if(typeof t.upload=="string"&&(r.uploadStrategy=t.upload),typeof t.timeout=="number"&&(r.timeout=t.timeout),typeof t.projectName=="string"&&(r.projectName=t.projectName),typeof t.queueMaxAge=="string"){let l=he(t.queueMaxAge);l!==null&&(r.queueMaxAge=l);}typeof t.queueDirectory=="string"&&(r.queueDirectory=t.queueDirectory),typeof t.uploadArtifacts=="boolean"&&(r.uploadArtifacts=t.uploadArtifacts),typeof t.artifactMaxSizeMb=="number"&&(r.artifactMaxSizeMb=t.artifactMaxSizeMb);}let n=process.env.TESTRELIC_API_KEY;n&&n.length>0&&(r.apiKey=n);let o=process.env.TESTRELIC_CLOUD_ENDPOINT;o&&isValidEndpointUrl(o)&&(r.endpoint=o);let s=process.env.TESTRELIC_UPLOAD_STRATEGY;s&&["batch","realtime","both"].includes(s)&&(r.uploadStrategy=s);let i=process.env.TESTRELIC_CLOUD_TIMEOUT;if(i){let l=parseInt(i,10);!isNaN(l)&&l>=1e3&&l<=12e4&&(r.timeout=l);}let a=Object.freeze(r);return isValidCloudConfig(a)?a:me}var jr=["authorization","cookie","set-cookie","x-api-key"],zr=["password","secret","token","apiKey","api_key"],qr=1024*1024;function Gr(e){let t=e??{},r=process.env.TESTRELIC_CAPTURE_NETWORK==="1"||process.env.TESTRELIC_CAPTURE_NETWORK?.toLowerCase()==="true";return Object.freeze({enabled:t.enabled??r??false,proxyPort:t.proxyPort??(process.env.TESTRELIC_PROXY_PORT?Number.parseInt(process.env.TESTRELIC_PROXY_PORT,10):8080),proxyHost:t.proxyHost??process.env.TESTRELIC_PROXY_HOST??"127.0.0.1",harPath:t.harPath??process.env.TESTRELIC_HAR_PATH??null,outputDir:t.outputDir??null,skipCertInstall:t.skipCertInstall??false,includeUrls:Object.freeze(t.includeUrls?[...t.includeUrls]:[]),excludeUrls:Object.freeze(t.excludeUrls?[...t.excludeUrls]:[]),redactHeaders:Object.freeze(t.redactHeaders?[...t.redactHeaders]:[...jr]),redactBodyFields:Object.freeze(t.redactBodyFields?[...t.redactBodyFields]:[...zr]),maxBodyBytes:t.maxBodyBytes??qr})}var Vr=new Set(["__proto__","constructor","prototype"]);function wt(e){if(typeof e!="object"||e===null)return false;for(let t of Object.keys(e))if(Vr.has(t))return true;return false}function Jr(e){if(typeof e!="object"||e===null||wt(e))return false;let t=e;return !(t.outputPath!==void 0&&typeof t.outputPath!="string"||t.htmlReportPath!==void 0&&typeof t.htmlReportPath!="string"||t.openReport!==void 0&&typeof t.openReport!="boolean"||t.includeScreenshots!==void 0&&typeof t.includeScreenshots!="boolean"||t.includeVideo!==void 0&&typeof t.includeVideo!="boolean"||t.includeAiAnalysis!==void 0&&typeof t.includeAiAnalysis!="boolean"||t.includeLogs!==void 0&&typeof t.includeLogs!="boolean"||t.includeFlowMetadata!==void 0&&typeof t.includeFlowMetadata!="boolean"||t.quiet!==void 0&&typeof t.quiet!="boolean"||t.metadata!==void 0&&t.metadata!==null&&(typeof t.metadata!="object"||wt(t.metadata)))}function Wr(e){if(e!==void 0&&!Jr(e))throw createError(ErrorCode.CONFIG_INVALID,"Invalid Maestro reporter configuration");let t=Object.create(null),r=e?.outputPath??"./test-results/testrelic-maestro.json";return t.outputPath=r,t.htmlReportPath=e?.htmlReportPath??r.replace(/\.json$/,".html"),t.openReport=e?.openReport??true,t.includeScreenshots=e?.includeScreenshots??true,t.includeVideo=e?.includeVideo??true,t.includeAiAnalysis=e?.includeAiAnalysis??true,t.includeLogs=e?.includeLogs??true,t.includeFlowMetadata=e?.includeFlowMetadata??true,t.flowsDir=e?.flowsDir??null,t.testRunId=e?.testRunId??null,t.metadata=e?.metadata??null,t.quiet=e?.quiet??false,t.reportMode=e?.reportMode??"batch",t.cloud=Kr(e?.cloud??null),t.network=Gr(e?.network),Object.freeze(t)}function Kr(e){let t=ye(process.cwd()),r=t?be(t):null,n=r?Y(r):null,o=xe(n,e??void 0);return o.apiKey?o:null}var Qr=new XMLParser({ignoreAttributes:false,attributeNamePrefix:"@_",allowBooleanAttributes:true,parseAttributeValue:true,trimValues:true});function X(e){return e==null?[]:Array.isArray(e)?e:[e]}function kt(e){return !e||typeof e!="object"?[]:X(e.property).map(n=>({name:String(n["@_name"]??""),value:String(n["@_value"]??"")}))}function Zr(e){let t=String(e["@_name"]??"unnamed"),r=String(e["@_classname"]??t),n=Number(e["@_time"]??0),o=e["@_id"]!=null?String(e["@_id"]):null,s=String(e["@_status"]??"").toUpperCase(),i=e.failure,a=e.error,l=e.skipped!==void 0,c="SUCCESS";return i?c="FAILURE":a?c="ERROR":l?c="SKIPPED":s==="FAILURE"||s==="FAILED"?c="FAILURE":s==="ERROR"?c="ERROR":s==="SKIPPED"&&(c="SKIPPED"),{id:o,name:t,classname:r,time:n,status:c,failureMessage:i?String(i["@_message"]??i["#text"]??""):null,failureType:i?String(i["@_type"]??""):null,errorMessage:a?String(a["@_message"]??a["#text"]??""):null,errorType:a?String(a["@_type"]??""):null,properties:kt(e.properties)}}function vt(e){let t=String(e["@_name"]??"Test Suite"),r=e["@_device"]!=null?String(e["@_device"]):null,n=Number(e["@_tests"]??0),o=Number(e["@_failures"]??0),s=Number(e["@_errors"]??0),i=Number(e["@_skipped"]??0),a=Number(e["@_time"]??0),c=X(e.testcase).map(Zr);return {name:t,device:r,tests:n,failures:o,errors:s,skipped:i,time:a,testCases:c,properties:kt(e.properties)}}function Ct(e){let t=Qr.parse(e),r=[];if(t.testsuites){let l=t.testsuites;r=X(l.testsuite).map(vt);}else t.testsuite&&(r=X(t.testsuite).map(vt));let n=0,o=0,s=0,i=0,a=0;for(let l of r)n+=l.tests,o+=l.failures,s+=l.errors,i+=l.skipped,a+=l.time;return {testSuites:r,totalTests:n,totalFailures:o,totalErrors:s,totalSkipped:i,totalTime:a}}function we(e){let t=readFileSync(e,"utf-8");return Ct(t)}var sn=new Set(["tapOn","doubleTapOn","longPressOn","inputText","eraseText","pasteText","swipe","scroll","scrollUntilVisible","hideKeyboard","pressKey","setClipboard","copyTextFrom"]),an=new Set(["assertVisible","assertNotVisible","assertTrue","assertScreenshot","assertNoDefectsWithAI","assertWithAI","assertCondition"]),ln=new Set(["launchApp","killApp","stopApp","clearState","openLink","back","clearKeychain"]),cn=new Set(["setAirplaneMode","toggleAirplaneMode","setLocation","setOrientation","setPermissions","addMedia","travel"]),dn=new Set(["takeScreenshot","startRecording","stopRecording"]),un=new Set(["runScript","evalScript"]),pn=new Set(["runFlow","repeat","retry","waitForAnimationToEnd","extendedWaitUntil"]),fn=new Set(["assertWithAI","assertNoDefectsWithAI","extractTextWithAI"]),gn=new Set(["inputText","pasteText"]),mn=200,hn=400;function Mt(e){return fn.has(e)?"ai":an.has(e)?"assertion":sn.has(e)?"interaction":ln.has(e)?"navigation":cn.has(e)?"device":dn.has(e)?"media":un.has(e)?"script":pn.has(e)?"flow_control":"other"}var yn={tapOnElement:"tapOn",assertCondition:"assertVisible",backPress:"back",applyConfiguration:"applyConfiguration",defineVariables:"defineVariables"};function Rt(e){let t=e.replace(/Command$/,"");return yn[t]??t}var bn=new Set(["metadata","command","commandName","name","status","duration","durationMs","timestamp","time","error","errorMessage","selector","commands","subSteps","children","sequenceNumber"]);function xn(e){for(let t of Object.keys(e)){if(bn.has(t))continue;let r=e[t];if(r&&typeof r=="object"&&!Array.isArray(r))return t}}function St(e){if(e.selector&&typeof e.selector=="object"){let t=e.selector;if(typeof t.textRegex=="string")return t.textRegex;if(typeof t.text=="string")return t.text;if(typeof t.id=="string")return `#${t.id}`}if(e.condition&&typeof e.condition=="object"){let t=e.condition,r=t.visible??t.notVisible;if(r){if(typeof r.textRegex=="string")return r.textRegex;if(typeof r.text=="string")return r.text}}if(typeof e.path=="string")return e.path}function Tt(e,t){return e.length<=t?e:`${e.slice(0,t)}\u2026`}function wn(e){return e.length===0?"":`[REDACTED ${e.length} chars]`}function At(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.x=="number"&&typeof t.y=="number")return `${t.x},${t.y}`}function It(e,t){let r={};switch(e){case "inputText":case "pasteText":{let n=t.text??t.value;typeof n=="string"&&(r.text=gn.has(e)?wn(n):n);break}case "swipe":case "scroll":case "scrollUntilVisible":{typeof t.direction=="string"&&(r.direction=t.direction);let n=At(t.start??t.startRelative),o=At(t.end??t.endRelative);n&&(r.start=n),o&&(r.end=o),typeof t.duration=="number"&&(r.swipeDurationMs=t.duration),typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "setLocation":{typeof t.latitude=="number"&&(r.latitude=t.latitude),typeof t.longitude=="number"&&(r.longitude=t.longitude);break}case "pressKey":case "back":{typeof t.key=="string"?r.key=t.key:typeof t.code=="string"&&(r.key=t.code);break}case "setOrientation":{typeof t.orientation=="string"&&(r.orientation=t.orientation);break}case "setAirplaneMode":case "toggleAirplaneMode":{(typeof t.value=="string"||typeof t.value=="boolean")&&(r.value=t.value);break}case "setPermissions":{t.permissions&&typeof t.permissions=="object"&&(r.permissions=t.permissions);break}case "addMedia":{Array.isArray(t.mediaPaths)?r.mediaPaths=t.mediaPaths:typeof t.path=="string"&&(r.mediaPaths=[t.path]);break}case "launchApp":case "killApp":case "stopApp":case "clearState":{let n=t.appId??t.packageName??t.bundleId;typeof n=="string"&&(r.appId=n),t.arguments&&(r.arguments=t.arguments);break}case "openLink":{typeof t.url=="string"?r.url=t.url:typeof t.link=="string"&&(r.url=t.link);break}case "runScript":case "evalScript":{typeof t.path=="string"&&(r.path=t.path);let n=t.script??t.scriptString;typeof n=="string"&&(r.script=Tt(n,mn)),typeof t.sourceDescription=="string"&&(r.sourceDescription=t.sourceDescription);break}case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":{let n=t.assertion??t.prompt??t.question;typeof n=="string"&&(r.prompt=Tt(n,hn));break}case "extendedWaitUntil":case "waitForAnimationToEnd":{typeof t.timeout=="number"&&(r.timeoutMs=t.timeout);break}case "repeat":case "retry":{typeof t.times=="number"&&(r.times=t.times),typeof t.maxRetries=="number"&&(r.maxRetries=t.maxRetries),typeof t.condition=="object"&&t.condition&&(r.condition=t.condition);break}case "runFlow":{typeof t.file=="string"&&(r.file=t.file),typeof t.flowId=="string"&&(r.flowId=t.flowId);break}default:for(let n of ["text","value","url"]){let o=t[n];if(typeof o=="string"||typeof o=="number"||typeof o=="boolean"){r[n]=o;break}}}return Object.keys(r).length>0?r:void 0}function ve(e,t,r){let n=[e.commands,t.commands,t.subSteps,t.children];for(let o of n)if(Array.isArray(o)&&o.length>0)return o.map((s,i)=>ke(s,i,r));return []}function ke(e,t,r){let n,o,s,i=[];if(typeof e.command=="object"&&e.command!==null&&!Array.isArray(e.command)){let y=e.command,h=Object.keys(y)[0]??`step-${t}`;n=Rt(h);let g=y[h]??{};o=St(g),s=It(n,g),i=ve(g,e,r);}else {let y=xn(e);if(y){n=Rt(y);let h=e[y]??{};o=St(h),s=It(n,h),i=ve(h,e,r);}else n=e.command??e.commandName??e.name??`step-${t}`,o=e.selector??void 0,i=ve({},e,r);}let a=e.metadata??{},l=vn(a.status??e.status),c=a.duration??e.duration??e.durationMs??0,d=typeof a.sequenceNumber=="number"?a.sequenceNumber:void 0,u;typeof a.timestamp=="number"?u=new Date(a.timestamp).toISOString():u=e.timestamp??e.time??r;let p=e.error??e.errorMessage??void 0;return {command:n,category:Mt(n),status:l,duration:c,timestamp:u,...o?{selector:o}:{},...p?{error:p}:{},...s?{details:s}:{},...d!==void 0?{sequenceNumber:d}:{},...i.length>0?{children:i}:{}}}function vn(e){if(!e)return "completed";let t=e.toLowerCase();return t==="failed"||t==="error"?"failed":t==="skipped"?"skipped":"completed"}function Et(e,t){let r=t??new Date().toISOString();try{let n=JSON.parse(e);if(Array.isArray(n))return n.map((o,s)=>ke(o,s,r));if(typeof n=="object"&&n!==null){let o=n,s=o.commands??o.steps??o.data;if(Array.isArray(s))return s.map((i,a)=>ke(i,a,r))}return []}catch{return []}}function Ce(e,t){try{let r=readFileSync(e,"utf-8");return Et(r,t)}catch{return []}}function Re(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t).startsWith("commands")&&t.endsWith(".json")).map(t=>join(e,t))}catch{return []}}function An(e){let t=[];for(let r of e)if(typeof r=="object"&&r!==null){let n=r;if(typeof n.runFlow=="string")t.push(n.runFlow);else if(typeof n.runFlow=="object"&&n.runFlow!==null){let o=n.runFlow;typeof o.file=="string"&&t.push(o.file);}}return t}function Pt(e){if(!e)return [];let t=[],r=Array.isArray(e)?e:[e];for(let n of r)if(typeof n=="string")t.push(n);else if(typeof n=="object"&&n!==null){let o=n;if(typeof o.runFlow=="string")t.push(o.runFlow);else if(typeof o.runFlow=="object"&&o.runFlow!==null){let s=o.runFlow;typeof s.file=="string"&&t.push(s.file);}typeof o.runScript=="string"&&t.push(o.runScript);}return t}function _t(e,t){let r=e.split(/^---\s*$/m,2),n=r[0]??"",o=r[1]??"",s={};try{let b=parseDocument(n).toJS();typeof b=="object"&&b!==null&&!Array.isArray(b)&&(s=b);}catch{}let i=[];if(o.trim())try{let b=parseDocument(o).toJS();Array.isArray(b)&&(i=b);}catch{}let a=typeof s.appId=="string"?s.appId:null,l=typeof s.name=="string"?s.name:null,c=[];if(Array.isArray(s.tags))for(let g of s.tags)typeof g=="string"&&c.push(g);let d={};if(typeof s.env=="object"&&s.env!==null&&!Array.isArray(s.env))for(let[g,b]of Object.entries(s.env))d[g]=String(b);let u={};if(typeof s.properties=="object"&&s.properties!==null&&!Array.isArray(s.properties))for(let[g,b]of Object.entries(s.properties))u[g]=String(b);let p=Pt(s.onFlowStart),y=Pt(s.onFlowComplete),h=An(i);return {appId:a,name:l,tags:c,env:d,properties:u,onFlowStart:p,onFlowComplete:y,subflowRefs:h,filePath:t}}function Se(e){let t=readFileSync(e,"utf-8");return _t(t,e)}function Te(e){if(!existsSync(e))return [];let t=[];function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);if(s.isDirectory())r(i);else if(s.isFile()){let a=extname(s.name).toLowerCase();(a===".yaml"||a===".yml")&&t.push(i);}}}catch{}}return r(e),t}var _n=/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)\s+\[?\s*(\w+)\s*\]?\s+(.+)$/,Ln=/^\[?(\d{2}:\d{2}:\d{2}(?:\.\d+)?)\]?\s+\[?\s*(\w+)\s*\]?\s+(.+)$/;function Lt(e){let t=e.toUpperCase();return t==="DEBUG"||t==="TRACE"||t==="VERBOSE"?"DEBUG":t==="INFO"?"INFO":t==="WARN"||t==="WARNING"?"WARN":t==="ERROR"||t==="FATAL"||t==="SEVERE"?"ERROR":"INFO"}function Dn(e,t){let r=/^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/.exec(t);if(!r)return new Date().toISOString();let n=Number(r[1]),o=Number(r[2]),s=Number(r[3]),i=r[4]?Number(r[4].padEnd(3,"0")):0;return new Date(e.getFullYear(),e.getMonth(),e.getDate(),n,o,s,i).toISOString()}function Dt(e,t){let r=[],n=e.split(`
3
+ `),o=t instanceof Date?t:null,s=typeof t=="string"?t:t instanceof Date?`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`:new Date().toISOString().split("T")[0];for(let i of n){let a=i.trim();if(!a)continue;let l=_n.exec(a);if(l){r.push({timestamp:l[1],level:Lt(l[2]),message:l[3],source:null});continue}if(l=Ln.exec(a),l){let c=o?Dn(o,l[1]):`${s}T${l[1]}`;r.push({timestamp:c,level:Lt(l[2]),message:l[3],source:null});continue}if(r.length>0){let c=r[r.length-1];r[r.length-1]={...c,message:c.message+`
4
+ `+a};}}return r}function Ae(e,t){try{let r=readFileSync(e,"utf-8");return Dt(r,t)}catch{return []}}function Ie(e){for(let t of e){let r=t.message.toLowerCase();if(r.includes("android")||r.includes("adb")||r.includes("uiautomator")||r.includes("emulator"))return "android";if(r.includes("ios")||r.includes("xcuitest")||r.includes("simulator")||r.includes("xctest"))return "ios";if(r.includes("web driver")||r.includes("chrome")||r.includes("chromium"))return "web"}return "unknown"}function Me(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>basename(t)==="maestro.log"||t.endsWith(".log")).map(t=>join(e,t))}catch{return []}}var jn=/(?:defect|issue|bug|error|warning|problem)/i,zn=/(?:critical|severe|major|blocker)/i,qn=/(?:warning|moderate|minor)/i,Ee=/(?:cut[\s-]?off|overlap|truncat|misalign|overflow|clip|obscur|hidden\s+text|broken\s+layout)/i,Q=/(?:spelling|typo|misspell|grammar)/i,Z=/(?:i18n|internationali[sz]ation|locali[sz]ation|untranslated|missing\s+translation)/i,Le=/(?:layout|spacing|padding|margin|alignment|centering|position)/i,De=/(?:accessib|a11y|contrast|screen\s*reader|alt\s*text|aria)/i;function Fe(e){return Q.test(e)?"spelling":Z.test(e)?"i18n":De.test(e)?"accessibility":Le.test(e)?"layout":"ui"}function Pe(e){return zn.test(e)?"critical":qn.test(e)?"warning":"info"}function _e(e){return e.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim()}function Gn(e){let t=[],r=_e(e),n=/<li[^>]*>([\s\S]*?)<\/li>/gi,o;for(;(o=n.exec(e))!==null;){let s=o[1],i=_e(s);!i||i.length<5||(jn.test(i)||Ee.test(i)||Q.test(i)||Z.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}if(t.length===0){let s=/<p[^>]*>([\s\S]*?)<\/p>/gi;for(;(o=s.exec(e))!==null;){let i=_e(o[1]);!i||i.length<10||(Ee.test(i)||Q.test(i)||Z.test(i)||Le.test(i)||De.test(i))&&t.push({type:Fe(i),severity:Pe(i),description:i,location:null,screenshot:null});}}if(t.length===0&&r.length>20){let s=r.split(/[.!?]+/).filter(i=>i.trim().length>10);for(let i of s){let a=i.trim();(Ee.test(a)||Q.test(a)||Z.test(a)||Le.test(a)||De.test(a))&&t.push({type:Fe(a),severity:Pe(a),description:a,location:null,screenshot:null});}}return t}function Nt(e){let t=Gn(e);return {defects:t,totalDefects:t.length,hasIssues:t.length>0,rawHtml:e}}function Ne(e){try{let t=readFileSync(e,"utf-8");return Nt(t)}catch{return {defects:[],totalDefects:0,hasIssues:false,rawHtml:null}}}function Oe(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>{let r=basename(t).toLowerCase();return extname(t).toLowerCase()===".html"&&(r.includes("insight")||r.includes("ai")||r.includes("analysis"))}).map(t=>join(e,t))}catch{return []}}var Xn=new Set([".png",".jpg",".jpeg",".webp"]),Qn=new Set([".mp4",".webm",".mov"]);function Ot(e){let t=[];if(!existsSync(e))return t;function r(n){try{let o=readdirSync(n,{withFileTypes:!0});for(let s of o){let i=join(n,s.name);s.isDirectory()?r(i):s.isFile()&&t.push(i);}}catch{}}return r(e),t}function Ue(e,t){let r=[],n=[],o=[],s=[],i=[],a=null,l=[];e&&l.push(...Ot(e)),t&&l.push(...Ot(t));let c=new Set;for(let d of l){if(c.has(d))continue;c.add(d);let u=basename(d).toLowerCase(),p=extname(d).toLowerCase();if(Xn.has(p)){r.push(d);continue}if(Qn.has(p)){n.push(d);continue}if(u==="maestro.log"||p===".log"&&u.includes("maestro")){o.push(d);continue}if(u.startsWith("commands")&&p===".json"){s.push(d);continue}if(p===".html"&&(u.includes("insight")||u.includes("ai")||u.includes("analysis"))){i.push(d);continue}if(p===".xml"&&(u.includes("report")||u.includes("junit"))){a||(a=d);continue}}return {screenshotPaths:r,videoPaths:n,logPaths:o,commandJsonPaths:s,aiReportPaths:i,junitReportPath:a}}function Zn(e){return {screenshots:e.screenshotPaths.length,videos:e.videoPaths.length,logs:e.logPaths.length,commandFiles:e.commandJsonPaths.length,aiReports:e.aiReportPaths.length,junitReport:e.junitReportPath?1:0}}function eo(e){switch(e){case "interaction":return "ui_action";case "assertion":return "assertion";case "ai":return "assertion";case "navigation":return "navigation";case "device":return "custom_step";case "media":return "custom_step";case "script":return "custom_step";case "flow_control":return "custom_step";case "recording":return "custom_step";default:return "custom_step"}}function to(e){let t=e.details;if(t)switch(e.command){case "inputText":case "pasteText":if(typeof t.text=="string")return `${e.command} \u2192 ${t.text}`;break;case "swipe":case "scroll":case "scrollUntilVisible":if(typeof t.direction=="string")return `${e.command} ${t.direction}`;break;case "setLocation":if(typeof t.latitude=="number"&&typeof t.longitude=="number")return `setLocation ${t.latitude},${t.longitude}`;break;case "pressKey":if(typeof t.key=="string")return `pressKey ${t.key}`;break;case "setOrientation":if(typeof t.orientation=="string")return `setOrientation ${t.orientation}`;break;case "launchApp":case "killApp":case "stopApp":case "clearState":if(typeof t.appId=="string")return `${e.command} ${t.appId}`;break;case "openLink":if(typeof t.url=="string")return `openLink ${t.url}`;break;case "runScript":case "evalScript":if(typeof t.path=="string")return `${e.command} ${t.path}`;if(typeof t.sourceDescription=="string")return `${e.command} ${t.sourceDescription}`;if(typeof t.script=="string")return `${e.command} ${t.script}`;break;case "assertWithAI":case "assertNoDefectsWithAI":case "extractTextWithAI":if(typeof t.prompt=="string")return `${e.command} \u2192 ${t.prompt}`;break;case "retry":if(typeof t.maxRetries=="number")return `retry \xD7 ${t.maxRetries}`;break;case "repeat":if(typeof t.times=="number")return `repeat \xD7 ${t.times}`;break;case "runFlow":if(typeof t.file=="string")return `runFlow ${t.file}`;break}return e.selector?`${e.command} \u2192 ${e.selector}`:e.command}function He(e,t){let r=Date.parse(e.timestamp),n=Number.isFinite(r)&&Number.isFinite(t)?Math.max(0,(r-t)/1e3):null,o=(e.children??[]).map(s=>He(s,t));return {title:to(e),category:eo(e.category),status:e.status==="failed"?"failed":"passed",duration:e.duration,timestamp:e.timestamp,videoOffset:n,error:e.error??null,children:o}}function ro(e,t){let r=Date.parse(e.timestamp),n=Date.parse(t.timestamp);return Number.isFinite(r)&&Number.isFinite(n)&&r!==n?r-n:0}function no(e,t){let r=Date.parse(e.startedAt),n=[...e.commands].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),o=[...e.assertions].sort((l,c)=>{let d=Date.parse(l.timestamp),u=Date.parse(c.timestamp);if(Number.isFinite(d)&&Number.isFinite(u)&&d!==u)return d-u;let p=l.sequenceNumber??0,y=c.sequenceNumber??0;return p-y}),s=[...n.map(l=>He(l,r)),...o.map(l=>He(l,r))];s.sort(ro);let i=e.screenshotPaths.length>0||e.videoPath?{screenshot:e.screenshotPaths[0]??void 0,video:e.videoPath??void 0}:null,a=[...e.tags];return e.platform!=="unknown"&&!a.includes(e.platform)&&a.push(e.platform),{title:e.flowName,status:e.status,duration:e.duration,startedAt:e.startedAt,completedAt:e.completedAt,retryCount:0,tags:a,failure:e.failureMessage?{message:e.failureMessage,line:null,code:null,stack:null}:null,testId:`${e.flowFile}::${e.flowName}`,filePath:e.flowFile,suiteName:e.appId??"maestro-suite",testType:"mobile",isFlaky:false,retryStatus:null,expectedStatus:"passed",actualStatus:e.status,artifacts:i,networkRequests:null,apiCalls:t.length>0?[...t]:null,apiAssertions:null,actions:s.length>0?s:null,consoleLogs:null}}function Ut(e,t){let r=`${e.flowFile}::${e.flowName}`,n=t?.get(r)??[],o=no(e,n);return {url:e.appId??"maestro-flow",navigationType:"page_load",visitedAt:e.startedAt,duration:e.duration,specFile:e.flowFile,domContentLoadedAt:null,networkIdleAt:null,networkStats:null,tests:[o]}}function $e(e,t){return e.map(r=>Ut(r,t))}var Ht={"2xx":0,"3xx":0,"4xx":0,"5xx":0,error:0};function oo(e){return e===null?"error":e>=200&&e<300?"2xx":e>=300&&e<400?"3xx":e>=400&&e<500?"4xx":e>=500&&e<600?"5xx":"error"}function Be(e,t){if(e.length===0)return null;let r=Math.min(e.length-1,Math.floor(t/100*e.length));return e[r]}function so(e){if(e.length===0)return {totalApiCalls:0,uniqueApiUrls:0,apiCallsByMethod:{},apiCallsByStatusRange:{...Ht},apiResponseTime:null};let t={},r={...Ht},n=new Set,o=[];for(let i of e)t[i.method]=(t[i.method]??0)+1,r[oo(i.responseStatusCode)]+=1,n.add(i.url),Number.isFinite(i.responseTimeMs)&&i.responseTimeMs>0&&o.push(i.responseTimeMs);o.sort((i,a)=>i-a);let s=o.length>0?{p50:Be(o,50)??0,p95:Be(o,95)??0,p99:Be(o,99)??0,avg:o.reduce((i,a)=>i+a,0)/o.length,min:o[0],max:o[o.length-1]}:null;return {totalApiCalls:e.length,uniqueApiUrls:n.size,apiCallsByMethod:t,apiCallsByStatusRange:r,apiResponseTime:s}}function G(e){let t=0,r=0,n=0,o=0,s=0,i=0,a=0,l=0,c=0,d=e.length,u=0,p={},y=new Set,h=[];for(let b of e){y.add(b.url);for(let x of b.tests){switch(t++,x.status){case "passed":r++;break;case "failed":n++;break;case "flaky":o++;break;case "skipped":s++;break;case "timedout":i++;break}if(x.actions)for(let T of x.actions)if(u++,T.category==="assertion")a++,T.status==="passed"?l++:c++;else {let R=T.category;p[R]=(p[R]??0)+1;}x.apiCalls&&x.apiCalls.length>0&&h.push(...x.apiCalls);}}let g=so(h);return {total:t,passed:r,failed:n,flaky:o,skipped:s,timedout:i,...g,totalAssertions:a,passedAssertions:l,failedAssertions:c,totalNavigations:d,uniqueNavigationUrls:y.size,totalTimelineSteps:e.length,totalActionSteps:u,actionStepsByCategory:p}}var $t=`
5
5
  /* \u2500\u2500 Theme Variables (verbatim from Appium) \u2500\u2500 */
6
6
  :root,[data-theme="dark"]{
7
7
  --bg:#0f1117;--bg-1:#161b22;--bg-2:#1c2128;--bg-3:#21262d;--bg-code:#13111c;
@@ -1142,7 +1142,7 @@ document.addEventListener('input',function(e){
1142
1142
  document.addEventListener('keydown',function(e){
1143
1143
  if(e.key==='Escape'&&$('drawer').classList.contains('open'))closeDrawer();
1144
1144
  });
1145
- `;var so=`
1145
+ `;var io=`
1146
1146
  (function(){
1147
1147
  var payload=JSON.parse(document.getElementById('report-data').textContent);
1148
1148
  var report=payload.report;
@@ -1225,15 +1225,15 @@ document.addEventListener('keydown',function(e){
1225
1225
  <div class="drawer-body" id="drawer-body"></div>
1226
1226
  </aside>
1227
1227
  <script id="report-data" type="application/json">${t}</script>
1228
- <script>${so}</script>
1228
+ <script>${io}</script>
1229
1229
  </body>
1230
- </html>`}function ze(e,t,r,n){let o=resolve(n),s=dirname(o);existsSync(s)||mkdirSync(s,{recursive:true});let a=JSON.stringify({report:e,aiDefects:t,screenshotPaths:r}),l=je(a);writeFileSync(o,l,"utf-8");}function po(e){let t=60-e.length;return t>0?e+" ".repeat(t):e}function O(e){return `\u2502 ${po(e)} \u2502
1230
+ </html>`}function ze(e,t,r,n){let o=resolve(n),s=dirname(o);existsSync(s)||mkdirSync(s,{recursive:true});let a=JSON.stringify({report:e,aiDefects:t,screenshotPaths:r}),l=je(a);writeFileSync(o,l,"utf-8");}function fo(e){let t=60-e.length;return t>0?e+" ".repeat(t):e}function O(e){return `\u2502 ${fo(e)} \u2502
1231
1231
  `}function qe(e,t,r,n,o){if(n||e.total===0)return;let s=`\u250C${"\u2500".repeat(62)}\u2510
1232
1232
  `,i=`\u2514${"\u2500".repeat(62)}\u2518
1233
1233
  `,a=O(""),l=s;l+=O("TestRelic AI - Maestro Test Report"),l+=a;let c=[];if(e.passed>0&&c.push(`${e.passed} \u2713`),e.failed>0&&c.push(`${e.failed} \u2717`),e.flaky>0&&c.push(`${e.flaky} \u26A0`),e.skipped>0&&c.push(`${e.skipped} skipped`),e.timedout>0&&c.push(`${e.timedout} timedout`),l+=O(`Flows: ${e.total} total (${c.join(" ")})`),e.totalAssertions>0&&(l+=O(`Assertions: ${e.totalAssertions} total (${e.passedAssertions} \u2713 ${e.failedAssertions} \u2717)`)),e.totalActionSteps>0){let d=[],u=e.actionStepsByCategory;u.ui_action&&d.push(`${u.ui_action} UI`),u.navigation&&d.push(`${u.navigation} nav`),u.custom_step&&d.push(`${u.custom_step} custom`);let p=d.length>0?` (${d.join(" ")})`:"";l+=O(`Steps: ${e.totalActionSteps} total${p}`);}if(o&&o.length>0){let d=o.filter(h=>h.severity==="critical").length,u=o.filter(h=>h.severity==="warning").length,p=o.filter(h=>h.severity==="info").length,y=[];d>0&&y.push(`${d} critical`),u>0&&y.push(`${u} warning`),p>0&&y.push(`${p} info`),l+=O(`AI Defects: ${o.length} found (${y.join(" ")})`);}l+=O(`Report: ${r}`),l+=O(`Data: ${t}`),l+=i,l+=`For more information visit us at https://docs.testrelic.ai
1234
- `,process.stderr.write(l);}function Ge(e){let t=process.platform,r;t==="darwin"?r=`open "${e}"`:t==="win32"?r=`start "" "${e}"`:r=`xdg-open "${e}"`,exec(r,()=>{});}function wo(){let e=[];try{let r=dirname(fileURLToPath(import.meta.url));e.push(join(r,"proxy-addon","testrelic_capture.py")),e.push(join(r,"..","src","proxy-addon","testrelic_capture.py"));}catch{}let t=globalThis.__dirname;t&&e.push(join(t,"proxy-addon","testrelic_capture.py"));for(let r of e)if(existsSync(r))return resolve(r);return null}function vo(e){if(e)return mkdirSync(e,{recursive:true}),e;let t=randomBytes(6).toString("hex"),r=join(tmpdir(),`testrelic-maestro-network-${t}`);return mkdirSync(r,{recursive:true}),r}async function ko(){return new Promise(e=>{let t=spawn("mitmdump",["--version"],{shell:true}),r=false,n=o=>{r||(r=true,e(o));};t.on("error",()=>n(false)),t.on("close",o=>n(o===0)),setTimeout(()=>{try{t.kill();}catch{}n(false);},5e3);})}async function Xt(e){let{config:t,verbose:r=true}=e;if(!t.enabled)return null;if(!await ko())return r&&process.stderr.write("\u26A0 TestRelic: --capture-network requested but `mitmdump` is not on PATH.\n Install mitmproxy (`brew install mitmproxy` / `pipx install mitmproxy`)\n or supply --har-path to import a HAR file instead.\n"),null;let n=wo();if(!n)return r&&process.stderr.write(`\u26A0 TestRelic: network-capture addon not found in package; skipping capture.
1235
- `),null;let o=vo(e.outputDir??t.outputDir??void 0),s=join(o,"network.jsonl"),i=["--listen-host",t.proxyHost,"--listen-port",String(t.proxyPort),"-s",n,"--set",`testrelic_output=${s}`,"--set",`testrelic_redact_headers=${t.redactHeaders.join(",")}`,"--set",`testrelic_redact_body_fields=${t.redactBodyFields.join(",")}`,"--set",`testrelic_max_body_bytes=${t.maxBodyBytes}`,"--set","console_eventlog_verbosity=warn","--set","termlog_verbosity=warn"],a;try{a=spawn("mitmdump",i,{stdio:["ignore","pipe","pipe"],shell:!0});}catch(c){return r&&process.stderr.write(`\u26A0 TestRelic: failed to spawn mitmdump: ${c.message}
1236
- `),null}a.stdout?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),a.stderr?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),await new Promise(c=>setTimeout(c,750));let l=()=>new Promise(c=>{if(a.killed||a.exitCode!==null){c();return}let d=false,u=()=>{d||(d=true,c());};a.once("close",u),a.once("exit",u);try{a.kill("SIGINT");}catch{try{a.kill();}catch{}}setTimeout(()=>{if(!d){try{a.kill("SIGKILL");}catch{}u();}},4e3);});return {outputPath:s,outputDir:o,host:t.proxyHost,port:t.proxyPort,stop:l}}var $={teardown:async()=>{}};function er(e){let t=spawnSync(e,["--version"],{shell:true,stdio:"ignore"});return t.error===void 0||t.error.code!=="ENOENT"}function E(e,t){e||process.stderr.write(`${t}
1234
+ `,process.stderr.write(l);}function Ge(e){let t=process.platform,r,n;t==="darwin"?(r="open",n=[e]):t==="win32"?(r="cmd",n=["/c","start","",e]):(r="xdg-open",n=[e]),execFile(r,n,()=>{});}function vo(){let e=[];try{let r=dirname(fileURLToPath(import.meta.url));e.push(join(r,"proxy-addon","testrelic_capture.py")),e.push(join(r,"..","src","proxy-addon","testrelic_capture.py"));}catch{}let t=globalThis.__dirname;t&&e.push(join(t,"proxy-addon","testrelic_capture.py"));for(let r of e)if(existsSync(r))return resolve(r);return null}function ko(e){if(e)return mkdirSync(e,{recursive:true}),e;let t=randomBytes(6).toString("hex"),r=join(tmpdir(),`testrelic-maestro-network-${t}`);return mkdirSync(r,{recursive:true}),r}async function Co(){return new Promise(e=>{let t=spawn("mitmdump",["--version"]),r=false,n=o=>{r||(r=true,e(o));};t.on("error",()=>n(false)),t.on("close",o=>n(o===0)),setTimeout(()=>{try{t.kill();}catch{}n(false);},5e3);})}async function Xt(e){let{config:t,verbose:r=true}=e;if(!t.enabled)return null;if(!await Co())return r&&process.stderr.write("\u26A0 TestRelic: --capture-network requested but `mitmdump` is not on PATH.\n Install mitmproxy (`brew install mitmproxy` / `pipx install mitmproxy`)\n or supply --har-path to import a HAR file instead.\n"),null;let n=vo();if(!n)return r&&process.stderr.write(`\u26A0 TestRelic: network-capture addon not found in package; skipping capture.
1235
+ `),null;let o=ko(e.outputDir??t.outputDir??void 0),s=join(o,"network.jsonl"),i=["--listen-host",t.proxyHost,"--listen-port",String(t.proxyPort),"-s",n,"--set",`testrelic_output=${s}`,"--set",`testrelic_redact_headers=${t.redactHeaders.join(",")}`,"--set",`testrelic_redact_body_fields=${t.redactBodyFields.join(",")}`,"--set",`testrelic_max_body_bytes=${t.maxBodyBytes}`,"--set","console_eventlog_verbosity=warn","--set","termlog_verbosity=warn"],a;try{a=spawn("mitmdump",i,{stdio:["ignore","pipe","pipe"]});}catch(c){return r&&process.stderr.write(`\u26A0 TestRelic: failed to spawn mitmdump: ${c.message}
1236
+ `),null}a.stdout?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),a.stderr?.on("data",c=>{r&&process.stderr.write(`[mitmdump] ${c.toString("utf-8")}`);}),await new Promise(c=>setTimeout(c,750));let l=()=>new Promise(c=>{if(a.killed||a.exitCode!==null){c();return}let d=false,u=()=>{d||(d=true,c());};a.once("close",u),a.once("exit",u);try{a.kill("SIGINT");}catch{try{a.kill();}catch{}}setTimeout(()=>{if(!d){try{a.kill("SIGKILL");}catch{}u();}},4e3);});return {outputPath:s,outputDir:o,host:t.proxyHost,port:t.proxyPort,stop:l}}var $={teardown:async()=>{}};function er(e){let t=spawnSync(e,["--version"],{stdio:"ignore"});return t.error===void 0||t.error.code!=="ENOENT"}function E(e,t){e||process.stderr.write(`${t}
1237
1237
  `);}function U(e,t,r,n){e||(t==="android"?process.stderr.write(`\u2139 TestRelic: real-device Android capture \u2014 set the device proxy manually:
1238
1238
  Settings \u2192 Wi-Fi \u2192 (long-press your network) \u2192 Modify \u2192 Proxy: Manual
1239
1239
  Host: ${r} Port: ${n}
@@ -1244,33 +1244,33 @@ document.addEventListener('keydown',function(e){
1244
1244
  Then install + TRUST the mitmproxy CA:
1245
1245
  1. Open http://mitm.it from Safari on the device \u2192 install profile.
1246
1246
  2. Settings \u2192 General \u2192 About \u2192 Certificate Trust Settings \u2192 enable mitmproxy.
1247
- `));}async function Qt(e,t){return new Promise(r=>{let n=t?["-s",t,...e]:e,o=spawn("adb",n,{shell:true,stdio:["ignore","pipe","pipe"]}),s="",i="";o.stdout?.on("data",a=>{s+=a.toString();}),o.stderr?.on("data",a=>{i+=a.toString();}),o.on("error",()=>r({code:127,stdout:s,stderr:i||"adb not on PATH"})),o.on("close",a=>r({code:a??1,stdout:s,stderr:i}));})}async function To(e){let{deviceId:t,proxyHost:r,proxyPort:n,quiet:o,skipCertInstall:s}=e;if(!er("adb"))return E(o,"\u26A0 TestRelic: `adb` not on PATH; skipping automatic Android proxy setup. See manual instructions:"),U(o,"android",r,n),$;let i=await Qt(["shell","settings","put","global","http_proxy",`${r}:${n}`],t);return i.code!==0?(E(o,`\u26A0 TestRelic: adb set proxy failed: ${i.stderr.trim()||"unknown error"}`),U(o,"android",r,n),$):(E(o,`\u2139 TestRelic: Android proxy set to ${r}:${n} on ${t??"default device"}.`),s||E(o,`\u2139 TestRelic: if HTTPS calls fail, install the mitmproxy CA on the emulator:
1247
+ `));}async function Qt(e,t){return new Promise(r=>{let n=t?["-s",t,...e]:e,o=spawn("adb",n,{stdio:["ignore","pipe","pipe"]}),s="",i="";o.stdout?.on("data",a=>{s+=a.toString();}),o.stderr?.on("data",a=>{i+=a.toString();}),o.on("error",()=>r({code:127,stdout:s,stderr:i||"adb not on PATH"})),o.on("close",a=>r({code:a??1,stdout:s,stderr:i}));})}async function Ao(e){let{deviceId:t,proxyHost:r,proxyPort:n,quiet:o,skipCertInstall:s}=e;if(!er("adb"))return E(o,"\u26A0 TestRelic: `adb` not on PATH; skipping automatic Android proxy setup. See manual instructions:"),U(o,"android",r,n),$;let i=await Qt(["shell","settings","put","global","http_proxy",`${r}:${n}`],t);return i.code!==0?(E(o,`\u26A0 TestRelic: adb set proxy failed: ${i.stderr.trim()||"unknown error"}`),U(o,"android",r,n),$):(E(o,`\u2139 TestRelic: Android proxy set to ${r}:${n} on ${t??"default device"}.`),s||E(o,`\u2139 TestRelic: if HTTPS calls fail, install the mitmproxy CA on the emulator:
1248
1248
  open http://mitm.it from Chrome on the emulator and follow prompts,
1249
1249
  OR for a system-level install:
1250
1250
  adb root && adb remount && adb push <mitm-ca>.0 /system/etc/security/cacerts/ && adb reboot
1251
- Set --skip-cert-install to silence this hint.`),{teardown:async()=>{await Qt(["shell","settings","put","global","http_proxy",":0"],t);}})}async function Ao(e){return new Promise(t=>{let r=spawn("xcrun",e,{shell:true,stdio:["ignore","pipe","pipe"]}),n="",o="";r.stdout?.on("data",s=>{n+=s.toString();}),r.stderr?.on("data",s=>{o+=s.toString();}),r.on("error",()=>t({code:127,stdout:n,stderr:o||"xcrun not on PATH"})),r.on("close",s=>t({code:s??1,stdout:n,stderr:o}));})}async function Io(e){let{proxyHost:t,proxyPort:r,quiet:n,skipCertInstall:o}=e;if(process.platform!=="darwin")return E(n,"\u26A0 TestRelic: iOS simulator capture requires macOS; the host is not Darwin. Skipping setup."),U(n,"ios",t,r),$;if(!er("xcrun"))return E(n,"\u26A0 TestRelic: `xcrun` not on PATH; skipping automatic iOS simulator setup."),U(n,"ios",t,r),$;if(!o){let s=join(process.env.HOME??"",".mitmproxy","mitmproxy-ca-cert.pem");if(existsSync(s)){let i=e.deviceId??"booted",a=await Ao(["simctl","keychain",i,"add-root-cert",s]);a.code===0?E(n,`\u2139 TestRelic: installed mitmproxy CA on iOS simulator (${i}).`):(E(n,`\u26A0 TestRelic: failed to add-root-cert via simctl: ${a.stderr.trim()}`),U(n,"ios",t,r));}else E(n,`\u26A0 TestRelic: mitmproxy CA not found at ${s}. Run mitmdump once to generate it,
1251
+ Set --skip-cert-install to silence this hint.`),{teardown:async()=>{await Qt(["shell","settings","put","global","http_proxy",":0"],t);}})}async function Io(e){return new Promise(t=>{let r=spawn("xcrun",e,{stdio:["ignore","pipe","pipe"]}),n="",o="";r.stdout?.on("data",s=>{n+=s.toString();}),r.stderr?.on("data",s=>{o+=s.toString();}),r.on("error",()=>t({code:127,stdout:n,stderr:o||"xcrun not on PATH"})),r.on("close",s=>t({code:s??1,stdout:n,stderr:o}));})}async function Mo(e){let{proxyHost:t,proxyPort:r,quiet:n,skipCertInstall:o}=e;if(process.platform!=="darwin")return E(n,"\u26A0 TestRelic: iOS simulator capture requires macOS; the host is not Darwin. Skipping setup."),U(n,"ios",t,r),$;if(!er("xcrun"))return E(n,"\u26A0 TestRelic: `xcrun` not on PATH; skipping automatic iOS simulator setup."),U(n,"ios",t,r),$;if(!o){let s=join(process.env.HOME??"",".mitmproxy","mitmproxy-ca-cert.pem");if(existsSync(s)){let i=e.deviceId??"booted",a=await Io(["simctl","keychain",i,"add-root-cert",s]);a.code===0?E(n,`\u2139 TestRelic: installed mitmproxy CA on iOS simulator (${i}).`):(E(n,`\u26A0 TestRelic: failed to add-root-cert via simctl: ${a.stderr.trim()}`),U(n,"ios",t,r));}else E(n,`\u26A0 TestRelic: mitmproxy CA not found at ${s}. Run mitmdump once to generate it,
1252
1252
  then re-run with --capture-network. Falling back to manual instructions:`),U(n,"ios",t,r);}return E(n,`\u2139 TestRelic: in the iOS simulator, configure Wi-Fi \u2192 (i) \u2192 Manual proxy:
1253
1253
  Server: ${t} Port: ${r}
1254
- (We do not set host-wide \`networksetup\` proxy automatically; see docs.)`),$}async function tr(e){switch(e.platform){case "android":return To(e);case "ios":return Io(e);case "web":return E(e.quiet,"\u2139 TestRelic: --capture-network ignored for Maestro web flows (browser already handles HTTP)."),$;default:return E(e.quiet,"\u26A0 TestRelic: target platform unknown; printing manual proxy setup instructions:"),U(e.quiet,"android",e.proxyHost,e.proxyPort),U(e.quiet,"ios",e.proxyHost,e.proxyPort),$}}function _o(){let e=randomBytes(8).toString("hex");return join(tmpdir(),`testrelic-maestro-${e}`)}function nr(e,t){let r=[];e.platform&&r.push("--platform",e.platform),e.device&&r.push("--device",e.device),r.push("test");let n=join(t,"report.xml"),o=join(t,"artifacts"),s=join(t,"debug");if(r.push("--format","junit"),r.push("--output",n),r.push("--test-output-dir",o),r.push("--debug-output",s),e.analyze&&r.push("--analyze"),e.includeTags&&r.push("--include-tags",e.includeTags),e.excludeTags&&r.push("--exclude-tags",e.excludeTags),e.shards&&e.shards>1&&r.push("--shards",String(e.shards)),e.config&&r.push("--config",e.config),e.env)for(let[i,a]of Object.entries(e.env))r.push("-e",`${i}=${a}`);return e.maestroArgs&&r.push(...e.maestroArgs),r.push(...e.flowPaths),r}function Lo(e){switch((e??"").toLowerCase()){case "android":return "android";case "ios":return "ios";case "web":return "web";default:return "unknown"}}function Do(e,t,r,n,o,s,i){return new Promise(a=>{let l=[],c=[],d=spawn("maestro",e,{stdio:["inherit","pipe","pipe"],shell:true});d.stdout.on("data",u=>{l.push(u),s||process.stdout.write(u);}),d.stderr.on("data",u=>{c.push(u),s||process.stderr.write(u);}),d.on("close",async u=>{try{await i();}catch{}a({exitCode:u??1,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:Buffer.concat(l).toString("utf-8"),stderr:Buffer.concat(c).toString("utf-8"),networkJsonlDir:o});}),d.on("error",async u=>{try{await i();}catch{}a({exitCode:127,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:"",stderr:`Failed to start maestro CLI: ${u.message}`,networkJsonlDir:o});});})}async function No(e,t={}){let r=e.outputDir?resolve(e.outputDir):_o();mkdirSync(join(r,"artifacts"),{recursive:true}),mkdirSync(join(r,"debug"),{recursive:true});let n=nr(e,r),o=join(r,"report.xml"),s=join(r,"artifacts"),i=join(r,"debug"),a=null,l=null,c=t.network;if(c?.enabled){let p=join(r,"network");a=await Xt({config:c,outputDir:p,verbose:!e.quiet}),a&&(l=await tr({platform:Lo(e.platform),deviceId:e.device,proxyHost:a.host,proxyPort:a.port,skipCertInstall:c.skipCertInstall,quiet:e.quiet}));}let d=a?.outputDir??null,u=async()=>{if(a&&await new Promise(p=>setTimeout(p,500)),l)try{await l.teardown();}catch{}if(a)try{await a.stop();}catch{}};return Do(n,o,s,i,d,e.quiet,u)}var ir="[REDACTED]";function or(e,t){if(!e)return null;let r=new Set(t.map(o=>o.toLowerCase())),n={};for(let[o,s]of Object.entries(e))n[o]=r.has(o.toLowerCase())?ir:s;return n}function Ve(e,t){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(n=>Ve(n,t));let r={};for(let[n,o]of Object.entries(e))r[n]=t.has(n)?ir:Ve(o,t);return r}function sr(e,t){if(!e||t.length===0)return e;try{let r=JSON.parse(e),n=Ve(r,new Set(t));return JSON.stringify(n)}catch{return e}}function Je(e,t,r){return {...e,requestHeaders:or(e.requestHeaders,t),responseHeaders:or(e.responseHeaders,t),requestBody:sr(e.requestBody,r),responseBody:e.isBinary?e.responseBody:sr(e.responseBody,r)}}function We(e,t,r){let n=o=>typeof o=="string"?e.includes(o):o.test(e);return r.some(n)?false:t.length===0?true:t.some(n)}function Ho(e){let t=e.trim();if(!t)return null;try{let r=JSON.parse(t);return typeof r.url!="string"||typeof r.method!="string"?null:{id:r.id??`api-call-${Date.now()}`,timestamp:r.timestamp??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:r.requestHeaders??null,requestBody:r.requestBody??null,responseStatusCode:r.responseStatusCode??null,responseStatusText:r.responseStatusText??null,responseHeaders:r.responseHeaders??null,responseBody:r.responseBody??null,responseTimeMs:typeof r.responseTimeMs=="number"?r.responseTimeMs:0,isBinary:r.isBinary??!1,error:r.error??null}}catch{return null}}function $o(e,t){let r=[];for(let n of e.split(/\r?\n/)){let o=Ho(n);o&&We(o.url,t.includeUrls,t.excludeUrls)&&r.push(Je(o,t.redactHeaders,t.redactBodyFields));}return r}function Bo(e,t){try{return $o(readFileSync(e,"utf-8"),t)}catch{return []}}function jo(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>t.endsWith(".jsonl")).map(t=>join(e,t))}catch{return []}}function ar(e){if(!e||e.length===0)return null;let t={};for(let r of e)typeof r.name=="string"&&typeof r.value=="string"&&(t[r.name]=r.value);return Object.keys(t).length>0?t:null}function zo(e){return e?typeof e.text=="string"?e.text:Array.isArray(e.params)?e.params.map(t=>`${encodeURIComponent(t.name)}=${encodeURIComponent(t.value??"")}`).join("&"):null:null}function qo(e){return e?/^(image|audio|video|application\/(octet-stream|pdf|zip|protobuf))/.test(e):false}function Go(e,t){let r=e.request,n=e.response;if(!r?.method||!r.url)return null;let o=n?.content,s=qo(o?.mimeType);return {id:`har-call-${t}`,timestamp:e.startedDateTime??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:ar(r.headers),requestBody:zo(r.postData),responseStatusCode:typeof n?.status=="number"&&n.status>0?n.status:null,responseStatusText:n?.statusText??null,responseHeaders:ar(n?.headers),responseBody:o?.text??null,responseTimeMs:typeof e.time=="number"?e.time:0,isBinary:s,error:null}}function Vo(e,t){let r;try{r=JSON.parse(e);}catch{return []}let n=r.log?.entries??[],o=[];return n.forEach((s,i)=>{let a=Go(s,i);a&&We(a.url,t.includeUrls,t.excludeUrls)&&o.push(Je(a,t.redactHeaders,t.redactBodyFields));}),o}function Jo(e,t){try{return Vo(readFileSync(e,"utf-8"),t)}catch{return []}}function Wo(e,t){let r=new Map;for(let o of t)r.set(o.testId,[]);if(e.length===0||t.length===0)return r;let n=t.map(o=>({testId:o.testId,startMs:Date.parse(o.startedAt),endMs:Date.parse(o.completedAt)}));for(let o of e){let s=Date.parse(o.timestamp);if(!Number.isFinite(s))continue;let i=n.find(l=>Number.isFinite(l.startMs)&&Number.isFinite(l.endMs)&&s>=l.startMs&&s<=l.endMs);if(i){r.get(i.testId).push(o);continue}let a=null;for(let l of n){if(!Number.isFinite(l.startMs)||!Number.isFinite(l.endMs))continue;let c=s<l.startMs?l.startMs-s:s-l.endMs;(!a||c<a.dist)&&(a={testId:l.testId,dist:c});}a&&r.get(a.testId).push(o);}return r}function dr(e,t,r){if(!t.enabled&&!t.harPath)return new Map;let n=[];if(e)for(let o of jo(e))n.push(...Bo(o,t));return t.harPath&&existsSync(t.harPath)&&n.push(...Jo(t.harPath,t)),n.length===0?new Map:Wo(n,r)}function ur(e){return e.map((t,r)=>({...t,id:`api-call-${r}`}))}var Xo=new Set(["localhost","127.0.0.1","0.0.0.0"]);function Ke(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&Xo.has(t.hostname)))throw createError(ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var Qo=3e3;async function ee(e){let t=new AbortController,r=setTimeout(()=>t.abort(),Qo);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function fr(e){return new Promise(t=>setTimeout(t,e))}async function pr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string")return r.message}catch{}return `HTTP ${e.status}`}async function te(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(s.ok){let a=await s.json();return {accessToken:a.accessToken,refreshToken:a.refreshToken,expiresIn:a.expiresIn,orgId:a.orgId,orgName:a.orgName,userId:a.userId,userName:a.userName}}if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;if(!isNaN(l)&&l>0){await fr(l);let c=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(c.ok){let d=await c.json();return {accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn,orgId:d.orgId,orgName:d.orgName,userId:d.userId,userName:d.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return s.status===400?{code:"validation_error",message:await pr(s),statusCode:400}:s.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:s.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await pr(s),statusCode:s.status}}catch(s){return s instanceof DOMException&&s.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(o);}}function re(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function Ye(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;!isNaN(l)&&l>0&&(await fr(l),s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!s.ok)return null;let i=await s.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn}}catch{return null}finally{clearTimeout(o);}}async function Xe(e,t,r,n,o,s){let i=new AbortController,a=setTimeout(()=>i.abort(),o);try{let l={gitId:r,displayName:n};s&&(l.branch=s);let c=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:i.signal});if(!c.ok)return null;let d=await c.json();return {repoId:d.repoId,displayName:d.displayName}}catch{return null}finally{clearTimeout(a);}}var ns=5e3;function H(e,t){try{return execSync(e,{cwd:t,timeout:ns,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function Qe(e){let t=H("git rev-parse --abbrev-ref HEAD",e),r=H("git rev-parse --short HEAD",e),n=H("git log -1 --pretty=%s",e),o=H("git log -1 --format=%an",e)??H("git config user.name",e),s=os(e),i=s?j(s):null;return {branch:t,commitSha:r,commitMessage:n,commitAuthor:o,remoteUrl:i}}function os(e){let t=H("git remote get-url origin",e);if(t)return t;let r=H("git remote",e);if(!r)return null;let n=r.split(`
1255
- `)[0]?.trim();return n?H(`git remote get-url ${n}`,e):null}function j(e){let t=e.trim();return t=t.replace(/^[a-z+]+:\/\//,""),t=t.replace(/^[^@]+@/,""),t=t.replace(/:(?!\d)/,"/"),t=t.replace(/\.git$/,""),t=t.replace(/\/+$/,""),t=t.replace(/^[^@/]+@/,""),t.toLowerCase()}function Ze(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function gr(e){try{let t=readFileSync(join(e,"package.json"),"utf-8"),r=JSON.parse(t);return typeof r.name=="string"&&r.name.length>0?r.name:null}catch{return null}}function z(e){let t=gr(e);return t||`local/${basename(e)}`}var ds="1.0.0",mr=10;function oe(e,t,r,n,o,s,i,a){try{mkdirSync(e,{recursive:!0});let l=Date.now(),c=`${l}-${t}-${r}.json`,d=join(e,c),u={version:ds,queuedAt:new Date(l).toISOString(),reason:n,retryCount:0,targetEndpoint:o,method:s,payload:i,headers:a},p=d+".tmp";writeFileSync(p,JSON.stringify(u,null,2),"utf-8"),renameSync(p,d);}catch(l){l.code==="ENOSPC"?process.stderr.write(`\u26A0 TestRelic: Disk full \u2014 unable to queue upload data.
1254
+ (We do not set host-wide \`networksetup\` proxy automatically; see docs.)`),$}async function tr(e){switch(e.platform){case "android":return Ao(e);case "ios":return Mo(e);case "web":return E(e.quiet,"\u2139 TestRelic: --capture-network ignored for Maestro web flows (browser already handles HTTP)."),$;default:return E(e.quiet,"\u26A0 TestRelic: target platform unknown; printing manual proxy setup instructions:"),U(e.quiet,"android",e.proxyHost,e.proxyPort),U(e.quiet,"ios",e.proxyHost,e.proxyPort),$}}function Lo(){let e=randomBytes(8).toString("hex");return join(tmpdir(),`testrelic-maestro-${e}`)}function nr(e,t){let r=[];e.platform&&r.push("--platform",e.platform),e.device&&r.push("--device",e.device),r.push("test");let n=join(t,"report.xml"),o=join(t,"artifacts"),s=join(t,"debug");if(r.push("--format","junit"),r.push("--output",n),r.push("--test-output-dir",o),r.push("--debug-output",s),e.analyze&&r.push("--analyze"),e.includeTags&&r.push("--include-tags",e.includeTags),e.excludeTags&&r.push("--exclude-tags",e.excludeTags),e.shards&&e.shards>1&&r.push("--shards",String(e.shards)),e.config&&r.push("--config",e.config),e.env)for(let[i,a]of Object.entries(e.env))r.push("-e",`${i}=${a}`);return e.maestroArgs&&r.push(...e.maestroArgs),r.push(...e.flowPaths),r}function Do(e){switch((e??"").toLowerCase()){case "android":return "android";case "ios":return "ios";case "web":return "web";default:return "unknown"}}function No(e,t,r,n,o,s,i){return new Promise(a=>{let l=[],c=[],d=spawn("maestro",e,{stdio:["inherit","pipe","pipe"]});d.stdout.on("data",u=>{l.push(u),s||process.stdout.write(u);}),d.stderr.on("data",u=>{c.push(u),s||process.stderr.write(u);}),d.on("close",async u=>{try{await i();}catch{}a({exitCode:u??1,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:Buffer.concat(l).toString("utf-8"),stderr:Buffer.concat(c).toString("utf-8"),networkJsonlDir:o});}),d.on("error",async u=>{try{await i();}catch{}a({exitCode:127,junitPath:t,testOutputDir:r,debugOutputDir:n,stdout:"",stderr:`Failed to start maestro CLI: ${u.message}`,networkJsonlDir:o});});})}async function Oo(e,t={}){let r=e.outputDir?resolve(e.outputDir):Lo();mkdirSync(join(r,"artifacts"),{recursive:true}),mkdirSync(join(r,"debug"),{recursive:true});let n=nr(e,r),o=join(r,"report.xml"),s=join(r,"artifacts"),i=join(r,"debug"),a=null,l=null,c=t.network;if(c?.enabled){let p=join(r,"network");a=await Xt({config:c,outputDir:p,verbose:!e.quiet}),a&&(l=await tr({platform:Do(e.platform),deviceId:e.device,proxyHost:a.host,proxyPort:a.port,skipCertInstall:c.skipCertInstall,quiet:e.quiet}));}let d=a?.outputDir??null,u=async()=>{if(a&&await new Promise(p=>setTimeout(p,500)),l)try{await l.teardown();}catch{}if(a)try{await a.stop();}catch{}};return No(n,o,s,i,d,e.quiet,u)}var ir="[REDACTED]";function or(e,t){if(!e)return null;let r=new Set(t.map(o=>o.toLowerCase())),n={};for(let[o,s]of Object.entries(e))n[o]=r.has(o.toLowerCase())?ir:s;return n}function Ve(e,t){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(n=>Ve(n,t));let r={};for(let[n,o]of Object.entries(e))r[n]=t.has(n)?ir:Ve(o,t);return r}function sr(e,t){if(!e||t.length===0)return e;try{let r=JSON.parse(e),n=Ve(r,new Set(t));return JSON.stringify(n)}catch{return e}}function Je(e,t,r){return {...e,requestHeaders:or(e.requestHeaders,t),responseHeaders:or(e.responseHeaders,t),requestBody:sr(e.requestBody,r),responseBody:e.isBinary?e.responseBody:sr(e.responseBody,r)}}function We(e,t,r){let n=o=>typeof o=="string"?e.includes(o):o.test(e);return r.some(n)?false:t.length===0?true:t.some(n)}function $o(e){let t=e.trim();if(!t)return null;try{let r=JSON.parse(t);return typeof r.url!="string"||typeof r.method!="string"?null:{id:r.id??`api-call-${Date.now()}`,timestamp:r.timestamp??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:r.requestHeaders??null,requestBody:r.requestBody??null,responseStatusCode:r.responseStatusCode??null,responseStatusText:r.responseStatusText??null,responseHeaders:r.responseHeaders??null,responseBody:r.responseBody??null,responseTimeMs:typeof r.responseTimeMs=="number"?r.responseTimeMs:0,isBinary:r.isBinary??!1,error:r.error??null}}catch{return null}}function Bo(e,t){let r=[];for(let n of e.split(/\r?\n/)){let o=$o(n);o&&We(o.url,t.includeUrls,t.excludeUrls)&&r.push(Je(o,t.redactHeaders,t.redactBodyFields));}return r}function jo(e,t){try{return Bo(readFileSync(e,"utf-8"),t)}catch{return []}}function zo(e){if(!existsSync(e))return [];try{return readdirSync(e,{recursive:!0}).map(String).filter(t=>t.endsWith(".jsonl")).map(t=>join(e,t))}catch{return []}}function ar(e){if(!e||e.length===0)return null;let t={};for(let r of e)typeof r.name=="string"&&typeof r.value=="string"&&(t[r.name]=r.value);return Object.keys(t).length>0?t:null}function qo(e){return e?typeof e.text=="string"?e.text:Array.isArray(e.params)?e.params.map(t=>`${encodeURIComponent(t.name)}=${encodeURIComponent(t.value??"")}`).join("&"):null:null}function Go(e){return e?/^(image|audio|video|application\/(octet-stream|pdf|zip|protobuf))/.test(e):false}function Vo(e,t){let r=e.request,n=e.response;if(!r?.method||!r.url)return null;let o=n?.content,s=Go(o?.mimeType);return {id:`har-call-${t}`,timestamp:e.startedDateTime??new Date().toISOString(),method:r.method,url:r.url,requestHeaders:ar(r.headers),requestBody:qo(r.postData),responseStatusCode:typeof n?.status=="number"&&n.status>0?n.status:null,responseStatusText:n?.statusText??null,responseHeaders:ar(n?.headers),responseBody:o?.text??null,responseTimeMs:typeof e.time=="number"?e.time:0,isBinary:s,error:null}}function Jo(e,t){let r;try{r=JSON.parse(e);}catch{return []}let n=r.log?.entries??[],o=[];return n.forEach((s,i)=>{let a=Vo(s,i);a&&We(a.url,t.includeUrls,t.excludeUrls)&&o.push(Je(a,t.redactHeaders,t.redactBodyFields));}),o}function Wo(e,t){try{return Jo(readFileSync(e,"utf-8"),t)}catch{return []}}function Ko(e,t){let r=new Map;for(let o of t)r.set(o.testId,[]);if(e.length===0||t.length===0)return r;let n=t.map(o=>({testId:o.testId,startMs:Date.parse(o.startedAt),endMs:Date.parse(o.completedAt)}));for(let o of e){let s=Date.parse(o.timestamp);if(!Number.isFinite(s))continue;let i=n.find(l=>Number.isFinite(l.startMs)&&Number.isFinite(l.endMs)&&s>=l.startMs&&s<=l.endMs);if(i){r.get(i.testId).push(o);continue}let a=null;for(let l of n){if(!Number.isFinite(l.startMs)||!Number.isFinite(l.endMs))continue;let c=s<l.startMs?l.startMs-s:s-l.endMs;(!a||c<a.dist)&&(a={testId:l.testId,dist:c});}a&&r.get(a.testId).push(o);}return r}function dr(e,t,r){if(!t.enabled&&!t.harPath)return new Map;let n=[];if(e)for(let o of zo(e))n.push(...jo(o,t));return t.harPath&&existsSync(t.harPath)&&n.push(...Wo(t.harPath,t)),n.length===0?new Map:Ko(n,r)}function ur(e){return e.map((t,r)=>({...t,id:`api-call-${r}`}))}var Qo=new Set(["localhost","127.0.0.1","0.0.0.0"]);function Ke(e){let t=new URL(e);if(t.protocol!=="https:"&&!(t.protocol==="http:"&&Qo.has(t.hostname)))throw createError(ErrorCode.CLOUD_CONFIG_INVALID,`HTTPS is required for cloud communication. Got: ${t.protocol}//${t.hostname}`)}var Zo=3e3;async function ee(e){let t=new AbortController,r=setTimeout(()=>t.abort(),Zo);try{return (await fetch(`${e}/health`,{method:"GET",signal:t.signal})).ok}catch{return false}finally{clearTimeout(r);}}async function fr(e){return new Promise(t=>setTimeout(t,e))}async function pr(e){try{let r=(await e.json()).error;if(r&&typeof r.message=="string")return r.message}catch{}return `HTTP ${e.status}`}async function te(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(s.ok){let a=await s.json();return {accessToken:a.accessToken,refreshToken:a.refreshToken,expiresIn:a.expiresIn,orgId:a.orgId,orgName:a.orgName,userId:a.userId,userName:a.userName}}if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;if(!isNaN(l)&&l>0){await fr(l);let c=await fetch(`${e}/sdk/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:t}),signal:n.signal});if(c.ok){let d=await c.json();return {accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn,orgId:d.orgId,orgName:d.orgName,userId:d.userId,userName:d.userName}}}return {code:"rate_limited",message:"Rate limited during token exchange.",statusCode:429}}return s.status===400?{code:"validation_error",message:await pr(s),statusCode:400}:s.status===401?{code:"invalid_key",message:"API key is invalid or has been revoked.",statusCode:401}:s.status===403?{code:"expired_key",message:"API key has expired.",statusCode:403}:{code:"server_error",message:await pr(s),statusCode:s.status}}catch(s){return s instanceof DOMException&&s.name==="AbortError"?{code:"timeout",message:"Token exchange timed out.",statusCode:null}:{code:"network_error",message:"Failed to reach cloud for token exchange.",statusCode:null}}finally{clearTimeout(o);}}function re(e){return "code"in e&&typeof e.code=="string"&&["invalid_key","expired_key","validation_error","rate_limited","server_error","network_error","timeout"].includes(e.code)}async function Ye(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal});if(s.status===429){let a=s.headers.get("Retry-After"),l=a?parseInt(a,10)*1e3:5e3;!isNaN(l)&&l>0&&(await fr(l),s=await fetch(`${e}/sdk/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t}),signal:n.signal}));}if(!s.ok)return null;let i=await s.json();return {accessToken:i.accessToken,refreshToken:i.refreshToken,expiresIn:i.expiresIn}}catch{return null}finally{clearTimeout(o);}}async function Xe(e,t,r,n,o,s){let i=new AbortController,a=setTimeout(()=>i.abort(),o);try{let l={gitId:r,displayName:n};s&&(l.branch=s);let c=await fetch(`${e}/repos/resolve`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(l),signal:i.signal});if(!c.ok)return null;let d=await c.json();return {repoId:d.repoId,displayName:d.displayName}}catch{return null}finally{clearTimeout(a);}}var os=5e3;function H(e,t){try{return execSync(e,{cwd:t,timeout:os,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}function Qe(e){let t=H("git rev-parse --abbrev-ref HEAD",e),r=H("git rev-parse --short HEAD",e),n=H("git log -1 --pretty=%s",e),o=H("git log -1 --format=%an",e)??H("git config user.name",e),s=ss(e),i=s?j(s):null;return {branch:t,commitSha:r,commitMessage:n,commitAuthor:o,remoteUrl:i}}function ss(e){let t=H("git remote get-url origin",e);if(t)return t;let r=H("git remote",e);if(!r)return null;let n=r.split(`
1255
+ `)[0]?.trim();return n?H(`git remote get-url ${n}`,e):null}function j(e){let t=e.trim();return t=t.replace(/^[a-z+]+:\/\//,""),t=t.replace(/^[^@]+@/,""),t=t.replace(/:(?!\d)/,"/"),t=t.replace(/\.git$/,""),t=t.replace(/\/+$/,""),t=t.replace(/^[^@/]+@/,""),t.toLowerCase()}function Ze(e){let t=e.split("/").filter(Boolean);return t[t.length-1]??e}function gr(e){try{let t=readFileSync(join(e,"package.json"),"utf-8"),r=JSON.parse(t);return typeof r.name=="string"&&r.name.length>0?r.name:null}catch{return null}}function z(e){let t=gr(e);return t||`local/${basename(e)}`}var us="1.0.0",mr=10;function oe(e,t,r,n,o,s,i,a){try{mkdirSync(e,{recursive:!0});let l=Date.now(),c=`${l}-${t}-${r}.json`,d=join(e,c),u={version:us,queuedAt:new Date(l).toISOString(),reason:n,retryCount:0,targetEndpoint:o,method:s,payload:i,headers:a},p=d+".tmp";writeFileSync(p,JSON.stringify(u,null,2),"utf-8"),renameSync(p,d);}catch(l){l.code==="ENOSPC"?process.stderr.write(`\u26A0 TestRelic: Disk full \u2014 unable to queue upload data.
1256
1256
  `):process.stderr.write(`\u26A0 TestRelic: Unable to queue upload data.
1257
- `);}}async function tt(e,t,r){let n;try{n=readdirSync(e).filter(s=>s.endsWith(".json")&&!s.endsWith(".tmp")).sort();}catch{return}if(n.length===0)return;let o=[];for(let s=0;s<n.length;s+=mr)o.push(n.slice(s,s+mr));for(let s of o)for(let i of s){let a=join(e,i);try{if(!statSync(a).isFile())continue;let c=readFileSync(a,"utf-8"),d=JSON.parse(c);if(!isValidQueueEntry(d)){unlinkSync(a);continue}let u=d;if((await fetch(u.targetEndpoint,{method:u.method,headers:{...u.headers,Authorization:`Bearer ${r}`},body:JSON.stringify(u.payload)})).ok)unlinkSync(a);else return}catch{return}}}function rt(e,t){try{let r=readdirSync(e).filter(o=>o.endsWith(".json")&&!o.endsWith(".tmp")),n=Date.now();for(let o of r){let s=join(e,o);try{let i=readFileSync(s,"utf-8"),l=JSON.parse(i).queuedAt;if(typeof l=="string"){let c=new Date(l).getTime();n-c>t&&unlinkSync(s);}}catch{try{unlinkSync(s);}catch{}}}}catch{}}var ys=3e5,bs=864e5,xs=6e4,br=3e4,xr="https://platform.testrelic.ai/settings/api-keys",J=class{constructor(t){this.gitMetadata=null;this.repoId=null;this.failureReason=null;this.flushPromise=null;this.healthCheckTimer=null;this.config=t,this.authState={mode:"pending",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null};}async initialize(){if(!this.config||!this.config.apiKey){this.setLocalMode("no_api_key"),process.stderr.write(`\u2139 TestRelic: No API key configured. Running in local mode.
1257
+ `);}}async function tt(e,t,r){let n;try{n=readdirSync(e).filter(s=>s.endsWith(".json")&&!s.endsWith(".tmp")).sort();}catch{return}if(n.length===0)return;let o=[];for(let s=0;s<n.length;s+=mr)o.push(n.slice(s,s+mr));for(let s of o)for(let i of s){let a=join(e,i);try{if(!statSync(a).isFile())continue;let c=readFileSync(a,"utf-8"),d=JSON.parse(c);if(!isValidQueueEntry(d)){unlinkSync(a);continue}let u=d;if((await fetch(u.targetEndpoint,{method:u.method,headers:{...u.headers,Authorization:`Bearer ${r}`},body:JSON.stringify(u.payload)})).ok)unlinkSync(a);else return}catch{return}}}function rt(e,t){try{let r=readdirSync(e).filter(o=>o.endsWith(".json")&&!o.endsWith(".tmp")),n=Date.now();for(let o of r){let s=join(e,o);try{let i=readFileSync(s,"utf-8"),l=JSON.parse(i).queuedAt;if(typeof l=="string"){let c=new Date(l).getTime();n-c>t&&unlinkSync(s);}}catch{try{unlinkSync(s);}catch{}}}}catch{}}var bs=3e5,xs=864e5,ws=6e4,br=3e4,xr="https://platform.testrelic.ai/settings/api-keys";function wr(e){return new Promise(t=>{let r=setTimeout(t,e);typeof r?.unref=="function"&&r.unref();})}var J=class{constructor(t){this.gitMetadata=null;this.repoId=null;this.failureReason=null;this.flushPromise=null;this.healthCheckTimer=null;this.config=t,this.authState={mode:"pending",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null};}async initialize(){if(!this.config||!this.config.apiKey){this.setLocalMode("no_api_key"),process.stderr.write(`\u2139 TestRelic: No API key configured. Running in local mode.
1258
1258
  `);return}try{if(Ke(this.config.endpoint),this.gitMetadata=Qe(),!await ee(this.config.endpoint)){this.setLocalMode("cloud_unreachable"),process.stderr.write(`\u26A0 TestRelic: Cloud unreachable. Switching to local mode.
1259
1259
  `);return}let r=await te(this.config.endpoint,this.config.apiKey,this.config.timeout);if(re(r)){this.handleAuthError(r.code,r.statusCode);return}let n=r;this.authState={mode:"cloud",accessToken:n.accessToken,refreshToken:n.refreshToken,expiresAt:Date.now()+n.expiresIn*1e3,orgId:n.orgId,orgName:n.orgName,userId:n.userId,userName:n.userName},process.stderr.write(`\u2713 TestRelic: Connected to cloud (${n.orgName} / ${n.userName})
1260
1260
  `),await this.resolveRepoId(),this.config.queueDirectory&&(rt(this.config.queueDirectory,this.config.queueMaxAge),this.startBackgroundFlush()),this.startHealthCheck();}catch(t){this.setLocalMode("unexpected_error"),process.stderr.write(`\u26A0 TestRelic: Unexpected error during cloud initialization. ${t instanceof Error?t.message:String(t)}
1261
- `);}}getMode(){return this.authState.mode}isCloudMode(){return this.authState.mode==="cloud"}isLocalMode(){return this.authState.mode==="local"}getAccessToken(){return this.authState.accessToken}getRepoId(){return this.repoId}getGitMetadata(){return this.gitMetadata}getConfig(){return this.config}getFailureReason(){return this.failureReason}getEndpoint(){return this.config?.endpoint??"https://platform.testrelic.ai/api/v1"}async ensureValidToken(){if(!this.isCloudMode()||!this.authState.accessToken)return false;let t=this.authState.expiresAt??0;if(Date.now()+ys<t)return true;if(!this.config||!this.authState.refreshToken)return this.switchToLocalMode("token_expired_no_refresh"),false;try{let r=await Ye(this.config.endpoint,this.authState.refreshToken,this.config.timeout);return r?(this.authState.accessToken=r.accessToken,this.authState.refreshToken=r.refreshToken,this.authState.expiresAt=Date.now()+r.expiresIn*1e3,!0):(this.switchToLocalMode("token_refresh_failed"),!1)}catch{return this.switchToLocalMode("token_refresh_error"),false}}switchToLocalMode(t){this.authState.mode!=="local"&&(this.authState.mode="local",this.failureReason=t,process.stderr.write(`\u26A0 TestRelic: Switched to local mode (${t}).
1262
- `));}async dispose(){if(this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=null),this.flushPromise){try{await Promise.race([this.flushPromise,new Promise(t=>setTimeout(t,br))]);}catch{}this.flushPromise=null;}this.authState={mode:"local",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null},this.repoId=null,this.gitMetadata=null;}setLocalMode(t){this.authState.mode="local",this.failureReason=t;}handleAuthError(t,r){switch(t){case "invalid_key":this.setLocalMode("invalid_api_key"),process.stderr.write(`\u26A0 TestRelic: API key is invalid or revoked. Running in local mode.
1261
+ `);}}getMode(){return this.authState.mode}isCloudMode(){return this.authState.mode==="cloud"}isLocalMode(){return this.authState.mode==="local"}getAccessToken(){return this.authState.accessToken}getRepoId(){return this.repoId}getGitMetadata(){return this.gitMetadata}getConfig(){return this.config}getFailureReason(){return this.failureReason}getEndpoint(){return this.config?.endpoint??"https://platform.testrelic.ai/api/v1"}async ensureValidToken(){if(!this.isCloudMode()||!this.authState.accessToken)return false;let t=this.authState.expiresAt??0;if(Date.now()+bs<t)return true;if(!this.config||!this.authState.refreshToken)return this.switchToLocalMode("token_expired_no_refresh"),false;try{let r=await Ye(this.config.endpoint,this.authState.refreshToken,this.config.timeout);return r?(this.authState.accessToken=r.accessToken,this.authState.refreshToken=r.refreshToken,this.authState.expiresAt=Date.now()+r.expiresIn*1e3,!0):(this.switchToLocalMode("token_refresh_failed"),!1)}catch{return this.switchToLocalMode("token_refresh_error"),false}}switchToLocalMode(t){this.authState.mode!=="local"&&(this.authState.mode="local",this.failureReason=t,process.stderr.write(`\u26A0 TestRelic: Switched to local mode (${t}).
1262
+ `));}async dispose(){if(this.healthCheckTimer&&(clearInterval(this.healthCheckTimer),this.healthCheckTimer=null),this.flushPromise){try{await Promise.race([this.flushPromise,wr(br)]);}catch{}this.flushPromise=null;}this.authState={mode:"local",accessToken:null,refreshToken:null,expiresAt:null,orgId:null,orgName:null,userId:null,userName:null},this.repoId=null,this.gitMetadata=null;}setLocalMode(t){this.authState.mode="local",this.failureReason=t;}handleAuthError(t,r){switch(t){case "invalid_key":this.setLocalMode("invalid_api_key"),process.stderr.write(`\u26A0 TestRelic: API key is invalid or revoked. Running in local mode.
1263
1263
  \u2192 Manage keys: ${xr}
1264
1264
  `);break;case "expired_key":this.setLocalMode("expired_api_key"),process.stderr.write(`\u26A0 TestRelic: API key has expired. Running in local mode.
1265
1265
  \u2192 Generate a new key: ${xr}
1266
1266
  `);break;case "rate_limited":this.setLocalMode("rate_limited"),process.stderr.write(`\u26A0 TestRelic: Rate limited during authentication. Running in local mode.
1267
1267
  `);break;default:this.setLocalMode(`auth_error_${r??"unknown"}`),process.stderr.write(`\u26A0 TestRelic: Cloud authentication failed. Running in local mode.
1268
- `);break}}async resolveRepoId(){if(!this.config||!this.authState.accessToken)return;let t=this.gitMetadata?.remoteUrl?j(this.gitMetadata.remoteUrl):null,r=t?Ze(t):this.config.projectName??z(process.cwd()),n=t??this.config.projectName??z(process.cwd()),o=this.readRepoCache(n);if(o){this.repoId=o.repoId;return}try{let s=await Xe(this.config.endpoint,this.authState.accessToken,n,r,this.config.timeout,this.gitMetadata?.branch);s&&(this.repoId=s.repoId,this.writeRepoCache(n,s.repoId,s.displayName));}catch{}}readRepoCache(t){if(!this.config)return null;let r=join(this.config.queueDirectory,"..","cache","repo.json");try{if(!existsSync(r))return null;let n=readFileSync(r,"utf-8"),o=JSON.parse(n);if(o.gitId!==t||Date.now()-o.resolvedAt>bs)return null;let s=this.hashApiKey();return s&&o.apiKeyHash!==s?null:o}catch{return null}}writeRepoCache(t,r,n){if(!this.config)return;let o=join(this.config.queueDirectory,"..","cache"),s=join(o,"repo.json");try{mkdirSync(o,{recursive:!0});let i={repoId:r,gitId:t,displayName:n,resolvedAt:Date.now(),apiKeyHash:this.hashApiKey()??""},a=s+".tmp";writeFileSync(a,JSON.stringify(i,null,2),"utf-8"),renameSync(a,s);}catch{}}hashApiKey(){return this.config?.apiKey?createHash("sha256").update(this.config.apiKey).digest("hex").substring(0,16):null}startBackgroundFlush(){if(!this.config||!this.authState.accessToken)return;let t=this.authState.accessToken,r=this.config.queueDirectory,n=this.config.endpoint;this.flushPromise=Promise.race([tt(r,n,t),new Promise(o=>setTimeout(o,br))]).catch(()=>{});}startHealthCheck(){if(!this.config)return;let t=this.config.endpoint;this.healthCheckTimer=setInterval(async()=>{if(!this.isCloudMode()&&!(!this.failureReason||!["cloud_unreachable","auth_timeout","network_error"].includes(this.failureReason)))try{if(!await ee(t))return;if(this.config?.apiKey){let n=await te(this.config.endpoint,this.config.apiKey,this.config.timeout);if(!re(n)){let o=n;this.authState={mode:"cloud",accessToken:o.accessToken,refreshToken:o.refreshToken,expiresAt:Date.now()+o.expiresIn*1e3,orgId:o.orgId,orgName:o.orgName,userId:o.userId,userName:o.userName},this.failureReason=null,process.stderr.write(`\u2713 TestRelic: Cloud connectivity restored.
1269
- `),this.startBackgroundFlush();}}}catch{}},xs);}};var vs=1048576,se=[1e3,3e3,9e3],ie=3;function le(e,t,r,n,o){let s=n?.provider&&n.provider!=="unknown"?n.provider:"local";return {runId:e.testRunId,repoGitId:t,startedAt:e.startedAt,summary:e.summary,timeline:e.timeline,environment:s,testFramework:"maestro",testType:"mobile",...o&&o.length>0?{tests:o}:{},...r?.branch?{branch:r.branch}:{},...r?.commitSha?{commit:r.commitSha}:{},...r?.commitMessage?{commitMessage:r.commitMessage}:{},...r?.commitAuthor?{commitAuthor:r.commitAuthor}:{},...e.completedAt?{finishedAt:e.completedAt}:{},...e.totalDuration?{duration:e.totalDuration}:{},...n?.provider?{ciProvider:n.provider}:{},...n?.runUrl?{ciRunUrl:n.runUrl}:{}}}async function ae(e){return new Promise(t=>setTimeout(t,e))}async function wr(e,t,r){for(let n=0;n<ie;n++)try{let o=await fetch(e,t);if(o.ok)return o;if(o.status===401&&r&&n===0){let s=await r();if(s){let i={...t,headers:{...t.headers,Authorization:`Bearer ${s}`}},a=await fetch(e,i);if(a.ok)return a}return null}if(o.status===429&&n<ie-1){let s=o.headers.get("Retry-After"),i=s?parseInt(s,10)*1e3:se[n];!isNaN(i)&&i>0?await ae(i):await ae(se[n]);continue}if(o.status>=500&&n<ie-1){await ae(se[n]);continue}return o}catch{if(n<ie-1){await ae(se[n]);continue}return null}return null}function ks(e){let t=JSON.stringify(e),r={"Content-Type":"application/json"};if(Buffer.byteLength(t,"utf-8")>vs){let n=gzipSync(Buffer.from(t,"utf-8"));return r["Content-Encoding"]="gzip",{body:n,headers:r}}return {body:t,headers:r}}async function ot(e,t,r,n){let o=`${e}/runs`,{body:s,headers:i}=ks(r);i.Authorization=`Bearer ${t}`;let a=await wr(o,{method:"POST",headers:i,body:s},n);return a?.ok?{success:true,statusCode:a.status,error:null}:a?.status===409?{success:true,statusCode:409,error:null}:{success:false,reason:a?`Upload failed with status ${a.status}`:"Upload failed after retries",statusCode:a?.status??null,payload:r,targetEndpoint:o,method:"POST"}}function Cs(e){let t={};for(let[r,n]of Object.entries(e))n!=null&&(t[r]=n);return t}async function Rs(e,t,r){let n=`${e}/runs/init`;try{let o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(Cs(r))});return o.ok?{runId:(await o.json()).runId}:null}catch{return null}}async function Ss(e,t,r,n){let o=`${e}/runs/${r}/finalize`;return (await wr(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}))?.ok??false}var Es=5,ce=[1e3,3e3,9e3],q=3,Fs={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".webm":"video/webm",".mp4":"video/mp4",".mov":"video/quicktime",".zip":"application/zip"},st=0,it=[];async function Ps(){st>=Es&&await new Promise(e=>it.push(e)),st++;}function _s(){st--,it.length>0&&it.shift()();}async function de(e){return new Promise(t=>setTimeout(t,e))}function Ls(e){let t=e.substring(e.lastIndexOf(".")).toLowerCase();return Fs[t]??"application/octet-stream"}function Ds(e){try{return statSync(e).size}catch{return 0}}async function Ns(e,t,r,n,o){let s=`${e}/artifacts/upload-url`,i=JSON.stringify({runId:r.runId,testId:r.testId,fileName:basename(r.filePath),contentType:o,type:r.type,sizeBytes:n});for(let a=0;a<q;a++)try{let l=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:i});if(l.ok)return await l.json();if(l.status>=500&&a<q-1){await de(ce[a]);continue}return null}catch{if(a<q-1){await de(ce[a]);continue}return null}return null}async function Os(e,t,r,n){for(let o=0;o<q;o++)try{let s=createReadStream(t),i=Readable.toWeb(s),a=await fetch(e,{method:"PUT",headers:{"Content-Type":r,"Content-Length":String(n)},body:i,duplex:"half"});if(a.ok)return !0;if(a.status>=500&&o<q-1){await de(ce[o]);continue}return !1}catch{if(o<q-1){await de(ce[o]);continue}return false}return false}async function Us(e,t,r){try{return (await fetch(`${e}/artifacts/confirm`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({artifactId:r})})).ok}catch{return false}}async function vr(e,t,r,n){let o=Ds(r.filePath);if(o===0)return {success:false,storageKey:null,artifactId:null,error:"file_not_found_or_empty"};if(o>n*1024*1024)return {success:false,storageKey:null,artifactId:null,error:"file_too_large"};let s=Ls(r.filePath);await Ps();try{let i=await Ns(e,t,r,o,s);if(!i)return {success:!1,storageKey:null,artifactId:null,error:"upload_url_request_failed"};if(!await Os(i.uploadUrl,r.filePath,s,o))return {success:!1,storageKey:i.storageKey,artifactId:i.artifactId,error:"presigned_put_failed"};let l=await Us(e,t,i.artifactId);return {success:l,storageKey:i.storageKey,artifactId:i.artifactId,error:l?null:"confirm_failed"}}finally{_s();}}async function at(e,t,r,n){let o=new Map,s=r.map(async i=>{let a=await vr(e,t,i,n);o.set(i.filePath,a);});return await Promise.allSettled(s),o}function Hs(e){return e.GITHUB_ACTIONS!=="true"?null:{provider:"github-actions",buildId:e.GITHUB_RUN_ID??null,commitSha:e.GITHUB_SHA??null,branch:e.GITHUB_REF_NAME??null,runUrl:e.GITHUB_SERVER_URL&&e.GITHUB_REPOSITORY&&e.GITHUB_RUN_ID?`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`:null}}function $s(e){return e.GITLAB_CI!=="true"?null:{provider:"gitlab-ci",buildId:e.CI_PIPELINE_ID??null,commitSha:e.CI_COMMIT_SHA??null,branch:e.CI_COMMIT_BRANCH??e.CI_COMMIT_REF_NAME??null,runUrl:e.CI_PIPELINE_URL??null}}function Bs(e){if(!e.JENKINS_URL)return null;let t=e.GIT_BRANCH??null;return t?.startsWith("origin/")&&(t=t.slice(7)),{provider:"jenkins",buildId:e.BUILD_ID??null,commitSha:e.GIT_COMMIT??null,branch:t,runUrl:e.BUILD_URL??null}}function js(e){return e.CIRCLECI!=="true"?null:{provider:"circleci",buildId:e.CIRCLE_BUILD_NUM??null,commitSha:e.CIRCLE_SHA1??null,branch:e.CIRCLE_BRANCH??null,runUrl:e.CIRCLE_BUILD_URL??null}}function zs(e){if(!e.BITBUCKET_PIPELINE_UUID)return null;let t=e.BITBUCKET_WORKSPACE&&e.BITBUCKET_REPO_SLUG&&e.BITBUCKET_PIPELINE_UUID?`https://bitbucket.org/${e.BITBUCKET_WORKSPACE}/${e.BITBUCKET_REPO_SLUG}/pipelines/results/${e.BITBUCKET_PIPELINE_UUID}`:null;return {provider:"bitbucket-pipelines",buildId:e.BITBUCKET_BUILD_NUMBER??null,commitSha:e.BITBUCKET_COMMIT??null,branch:e.BITBUCKET_BRANCH??null,runUrl:t}}var qs=[Hs,$s,Bs,js,zs];function ue(e){let t=e??process.env;for(let r of qs){let n=r(t);if(n)return n}return null}function Gs(e){let t=[];for(let r of e){let n=r,o=n.tests;if(!Array.isArray(o)||o.length===0){t.push(r);continue}for(let s of o){t.push({timestamp:s.startedAt,title:s.title,category:"test",navigationType:n.navigationType,url:n.url,visitedAt:n.visitedAt,duration:s.duration,status:s.status,test_status:s.status,test_id:s.testId,test_title:s.title,specfile:s.filePath,suiteName:s.suiteName,type:"test",...s.failure?{error:s.failure.message,errorMessage:s.failure.message}:{}});for(let i of s.actions??[])t.push({timestamp:i.timestamp,title:i.title,category:i.category,status:i.status,test_status:s.status,duration:i.duration,error:i.error,test_id:s.testId,test_title:s.title,specfile:s.filePath,url:n.url,type:i.category==="assertion"?"assert":"action"});}}return t}function kr(e){let r=e.getGitMetadata()?.remoteUrl;return r?j(r):e.getConfig()?.projectName??z(process.cwd())}async function lt(e,t,r,n,o,s,i,a,l,c,d){try{let u=d?.length??0,p=(a?.length??0)+(l?.length??0)+u>0;if(e.isCloudMode()&&p&&await e.ensureValidToken()){let h=e.getEndpoint(),g=e.getAccessToken(),b=t?.artifactMaxSizeMb??50,x=[];for(let R of a??[])x.push({filePath:R,runId:r,testId:"maestro-suite",type:"screenshot"});let T=new Set;for(let R of d??[])x.push({filePath:R.path,runId:r,testId:R.testId,type:"video"}),T.add(R.path);for(let R of l??[])T.has(R)||x.push({filePath:R,runId:r,testId:"maestro-suite",type:"video"});if(x.length>0){let R=await at(h,g,x,b),D=Array.from(R.entries()),I=D.filter(([,m])=>m.success).length,f=D.filter(([,m])=>!m.success);if(I>0){let m=x.filter(k=>k.type==="video").length,w=d?.length??0,v=x.filter(k=>k.type==="screenshot").length,S=[];if(v>0&&S.push(`${v} screenshot(s)`),m>0){let k=w>0?` (${w} per-flow)`:"";S.push(`${m} video(s)${k}`);}process.stderr.write(`\u2713 TestRelic: Uploaded ${I} artifact(s) [${S.join(", ")}] to cloud storage.
1268
+ `);break}}async resolveRepoId(){if(!this.config||!this.authState.accessToken)return;let t=this.gitMetadata?.remoteUrl?j(this.gitMetadata.remoteUrl):null,r=t?Ze(t):this.config.projectName??z(process.cwd()),n=t??this.config.projectName??z(process.cwd()),o=this.readRepoCache(n);if(o){this.repoId=o.repoId;return}try{let s=await Xe(this.config.endpoint,this.authState.accessToken,n,r,this.config.timeout,this.gitMetadata?.branch);s&&(this.repoId=s.repoId,this.writeRepoCache(n,s.repoId,s.displayName));}catch{}}readRepoCache(t){if(!this.config)return null;let r=join(this.config.queueDirectory,"..","cache","repo.json");try{if(!existsSync(r))return null;let n=readFileSync(r,"utf-8"),o=JSON.parse(n);if(o.gitId!==t||Date.now()-o.resolvedAt>xs)return null;let s=this.hashApiKey();return s&&o.apiKeyHash!==s?null:o}catch{return null}}writeRepoCache(t,r,n){if(!this.config)return;let o=join(this.config.queueDirectory,"..","cache"),s=join(o,"repo.json");try{mkdirSync(o,{recursive:!0});let i={repoId:r,gitId:t,displayName:n,resolvedAt:Date.now(),apiKeyHash:this.hashApiKey()??""},a=s+".tmp";writeFileSync(a,JSON.stringify(i,null,2),"utf-8"),renameSync(a,s);}catch{}}hashApiKey(){return this.config?.apiKey?createHash("sha256").update(this.config.apiKey).digest("hex").substring(0,16):null}startBackgroundFlush(){if(!this.config||!this.authState.accessToken)return;let t=this.authState.accessToken,r=this.config.queueDirectory,n=this.config.endpoint;this.flushPromise=Promise.race([tt(r,n,t),wr(br)]).catch(()=>{});}startHealthCheck(){if(!this.config)return;let t=this.config.endpoint;this.healthCheckTimer=setInterval(async()=>{if(!this.isCloudMode()&&!(!this.failureReason||!["cloud_unreachable","auth_timeout","network_error"].includes(this.failureReason)))try{if(!await ee(t))return;if(this.config?.apiKey){let n=await te(this.config.endpoint,this.config.apiKey,this.config.timeout);if(!re(n)){let o=n;this.authState={mode:"cloud",accessToken:o.accessToken,refreshToken:o.refreshToken,expiresAt:Date.now()+o.expiresIn*1e3,orgId:o.orgId,orgName:o.orgName,userId:o.userId,userName:o.userName},this.failureReason=null,process.stderr.write(`\u2713 TestRelic: Cloud connectivity restored.
1269
+ `),this.startBackgroundFlush();}}}catch{}},ws),typeof this.healthCheckTimer?.unref=="function"&&this.healthCheckTimer.unref();}};var ks=1048576,se=[1e3,3e3,9e3],ie=3;function le(e,t,r,n,o){let s=n?.provider&&n.provider!=="unknown"?n.provider:"local";return {runId:e.testRunId,repoGitId:t,startedAt:e.startedAt,summary:e.summary,timeline:e.timeline,environment:s,testFramework:"maestro",testType:"mobile",...o&&o.length>0?{tests:o}:{},...r?.branch?{branch:r.branch}:{},...r?.commitSha?{commit:r.commitSha}:{},...r?.commitMessage?{commitMessage:r.commitMessage}:{},...r?.commitAuthor?{commitAuthor:r.commitAuthor}:{},...e.completedAt?{finishedAt:e.completedAt}:{},...e.totalDuration?{duration:e.totalDuration}:{},...n?.provider?{ciProvider:n.provider}:{},...n?.runUrl?{ciRunUrl:n.runUrl}:{}}}async function ae(e){return new Promise(t=>setTimeout(t,e))}async function vr(e,t,r){for(let n=0;n<ie;n++)try{let o=await fetch(e,t);if(o.ok)return o;if(o.status===401&&r&&n===0){let s=await r();if(s){let i={...t,headers:{...t.headers,Authorization:`Bearer ${s}`}},a=await fetch(e,i);if(a.ok)return a}return null}if(o.status===429&&n<ie-1){let s=o.headers.get("Retry-After"),i=s?parseInt(s,10)*1e3:se[n];!isNaN(i)&&i>0?await ae(i):await ae(se[n]);continue}if(o.status>=500&&n<ie-1){await ae(se[n]);continue}return o}catch{if(n<ie-1){await ae(se[n]);continue}return null}return null}function Cs(e){let t=JSON.stringify(e),r={"Content-Type":"application/json"};if(Buffer.byteLength(t,"utf-8")>ks){let n=gzipSync(Buffer.from(t,"utf-8"));return r["Content-Encoding"]="gzip",{body:n,headers:r}}return {body:t,headers:r}}async function ot(e,t,r,n){let o=`${e}/runs`,{body:s,headers:i}=Cs(r);i.Authorization=`Bearer ${t}`;let a=await vr(o,{method:"POST",headers:i,body:s},n);return a?.ok?{success:true,statusCode:a.status,error:null}:a?.status===409?{success:true,statusCode:409,error:null}:{success:false,reason:a?`Upload failed with status ${a.status}`:"Upload failed after retries",statusCode:a?.status??null,payload:r,targetEndpoint:o,method:"POST"}}function Rs(e){let t={};for(let[r,n]of Object.entries(e))n!=null&&(t[r]=n);return t}async function Ss(e,t,r){let n=`${e}/runs/init`;try{let o=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(Rs(r))});return o.ok?{runId:(await o.json()).runId}:null}catch{return null}}async function Ts(e,t,r,n){let o=`${e}/runs/${r}/finalize`;return (await vr(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(n)}))?.ok??false}var Fs=5,ce=[1e3,3e3,9e3],q=3,Ps={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".webm":"video/webm",".mp4":"video/mp4",".mov":"video/quicktime",".zip":"application/zip"},st=0,it=[];async function _s(){st>=Fs&&await new Promise(e=>it.push(e)),st++;}function Ls(){st--,it.length>0&&it.shift()();}async function de(e){return new Promise(t=>setTimeout(t,e))}function Ds(e){let t=e.substring(e.lastIndexOf(".")).toLowerCase();return Ps[t]??"application/octet-stream"}function Ns(e){try{return statSync(e).size}catch{return 0}}async function Os(e,t,r,n,o){let s=`${e}/artifacts/upload-url`,i=JSON.stringify({runId:r.runId,testId:r.testId,fileName:basename(r.filePath),contentType:o,type:r.type,sizeBytes:n});for(let a=0;a<q;a++)try{let l=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:i});if(l.ok)return await l.json();if(l.status>=500&&a<q-1){await de(ce[a]);continue}return null}catch{if(a<q-1){await de(ce[a]);continue}return null}return null}async function Us(e,t,r,n){for(let o=0;o<q;o++)try{let s=createReadStream(t),i=Readable.toWeb(s),a=await fetch(e,{method:"PUT",headers:{"Content-Type":r,"Content-Length":String(n)},body:i,duplex:"half"});if(a.ok)return !0;if(a.status>=500&&o<q-1){await de(ce[o]);continue}return !1}catch{if(o<q-1){await de(ce[o]);continue}return false}return false}async function Hs(e,t,r){try{return (await fetch(`${e}/artifacts/confirm`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({artifactId:r})})).ok}catch{return false}}async function kr(e,t,r,n){let o=Ns(r.filePath);if(o===0)return {success:false,storageKey:null,artifactId:null,error:"file_not_found_or_empty"};if(o>n*1024*1024)return {success:false,storageKey:null,artifactId:null,error:"file_too_large"};let s=Ds(r.filePath);await _s();try{let i=await Os(e,t,r,o,s);if(!i)return {success:!1,storageKey:null,artifactId:null,error:"upload_url_request_failed"};if(!await Us(i.uploadUrl,r.filePath,s,o))return {success:!1,storageKey:i.storageKey,artifactId:i.artifactId,error:"presigned_put_failed"};let l=await Hs(e,t,i.artifactId);return {success:l,storageKey:i.storageKey,artifactId:i.artifactId,error:l?null:"confirm_failed"}}finally{Ls();}}async function at(e,t,r,n){let o=new Map,s=r.map(async i=>{let a=await kr(e,t,i,n);o.set(i.filePath,a);});return await Promise.allSettled(s),o}function $s(e){return e.GITHUB_ACTIONS!=="true"?null:{provider:"github-actions",buildId:e.GITHUB_RUN_ID??null,commitSha:e.GITHUB_SHA??null,branch:e.GITHUB_REF_NAME??null,runUrl:e.GITHUB_SERVER_URL&&e.GITHUB_REPOSITORY&&e.GITHUB_RUN_ID?`${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`:null}}function Bs(e){return e.GITLAB_CI!=="true"?null:{provider:"gitlab-ci",buildId:e.CI_PIPELINE_ID??null,commitSha:e.CI_COMMIT_SHA??null,branch:e.CI_COMMIT_BRANCH??e.CI_COMMIT_REF_NAME??null,runUrl:e.CI_PIPELINE_URL??null}}function js(e){if(!e.JENKINS_URL)return null;let t=e.GIT_BRANCH??null;return t?.startsWith("origin/")&&(t=t.slice(7)),{provider:"jenkins",buildId:e.BUILD_ID??null,commitSha:e.GIT_COMMIT??null,branch:t,runUrl:e.BUILD_URL??null}}function zs(e){return e.CIRCLECI!=="true"?null:{provider:"circleci",buildId:e.CIRCLE_BUILD_NUM??null,commitSha:e.CIRCLE_SHA1??null,branch:e.CIRCLE_BRANCH??null,runUrl:e.CIRCLE_BUILD_URL??null}}function qs(e){if(!e.BITBUCKET_PIPELINE_UUID)return null;let t=e.BITBUCKET_WORKSPACE&&e.BITBUCKET_REPO_SLUG&&e.BITBUCKET_PIPELINE_UUID?`https://bitbucket.org/${e.BITBUCKET_WORKSPACE}/${e.BITBUCKET_REPO_SLUG}/pipelines/results/${e.BITBUCKET_PIPELINE_UUID}`:null;return {provider:"bitbucket-pipelines",buildId:e.BITBUCKET_BUILD_NUMBER??null,commitSha:e.BITBUCKET_COMMIT??null,branch:e.BITBUCKET_BRANCH??null,runUrl:t}}var Gs=[$s,Bs,js,zs,qs];function ue(e){let t=e??process.env;for(let r of Gs){let n=r(t);if(n)return n}return null}function Vs(e){let t=[];for(let r of e){let n=r,o=n.tests;if(!Array.isArray(o)||o.length===0){t.push(r);continue}for(let s of o){t.push({timestamp:s.startedAt,title:s.title,category:"test",navigationType:n.navigationType,url:n.url,visitedAt:n.visitedAt,duration:s.duration,status:s.status,test_status:s.status,test_id:s.testId,test_title:s.title,specfile:s.filePath,suiteName:s.suiteName,type:"test",...s.failure?{error:s.failure.message,errorMessage:s.failure.message}:{}});for(let i of s.actions??[])t.push({timestamp:i.timestamp,title:i.title,category:i.category,status:i.status,test_status:s.status,duration:i.duration,error:i.error,test_id:s.testId,test_title:s.title,specfile:s.filePath,url:n.url,type:i.category==="assertion"?"assert":"action"});}}return t}function Cr(e){let r=e.getGitMetadata()?.remoteUrl;return r?j(r):e.getConfig()?.projectName??z(process.cwd())}async function lt(e,t,r,n,o,s,i,a,l,c,d){try{let u=d?.length??0,p=(a?.length??0)+(l?.length??0)+u>0;if(e.isCloudMode()&&p&&await e.ensureValidToken()){let h=e.getEndpoint(),g=e.getAccessToken(),b=t?.artifactMaxSizeMb??50,x=[];for(let R of a??[])x.push({filePath:R,runId:r,testId:"maestro-suite",type:"screenshot"});let T=new Set;for(let R of d??[])x.push({filePath:R.path,runId:r,testId:R.testId,type:"video"}),T.add(R.path);for(let R of l??[])T.has(R)||x.push({filePath:R,runId:r,testId:"maestro-suite",type:"video"});if(x.length>0){let R=await at(h,g,x,b),D=Array.from(R.entries()),I=D.filter(([,m])=>m.success).length,f=D.filter(([,m])=>!m.success);if(I>0){let m=x.filter(k=>k.type==="video").length,w=d?.length??0,v=x.filter(k=>k.type==="screenshot").length,S=[];if(v>0&&S.push(`${v} screenshot(s)`),m>0){let k=w>0?` (${w} per-flow)`:"";S.push(`${m} video(s)${k}`);}process.stderr.write(`\u2713 TestRelic: Uploaded ${I} artifact(s) [${S.join(", ")}] to cloud storage.
1270
1270
  `);}if(f.length>0){process.stderr.write(`\u26A0 TestRelic: ${f.length} artifact(s) failed to upload:
1271
1271
  `);for(let[m,w]of f){let v=x.find(k=>k.filePath===m),S=v?`[${v.type}] ${m}`:m;process.stderr.write(` \u2717 ${S} \u2014 reason: ${w.error??"unknown"}
1272
- `);}}}}if(e.isCloudMode())if(await e.ensureValidToken()){let h=e.getGitMetadata(),g=ue(),b=kr(e),x=Gs(n.timeline),T={...n,timeline:x},R=le(T,b,h,g,c),D=await ot(e.getEndpoint(),e.getAccessToken(),R,async()=>await e.ensureValidToken()?e.getAccessToken():null);if(D.success)process.stderr.write(`\u2713 TestRelic: Cloud upload succeeded \u2192 ${e.getEndpoint()}/runs/${r}
1272
+ `);}}}}if(e.isCloudMode())if(await e.ensureValidToken()){let h=e.getGitMetadata(),g=ue(),b=Cr(e),x=Vs(n.timeline),T={...n,timeline:x},R=le(T,b,h,g,c),D=await ot(e.getEndpoint(),e.getAccessToken(),R,async()=>await e.ensureValidToken()?e.getAccessToken():null);if(D.success)process.stderr.write(`\u2713 TestRelic: Cloud upload succeeded \u2192 ${e.getEndpoint()}/runs/${r}
1273
1273
  `);else {let I=D,f=t?.queueDirectory??".testrelic/queue";oe(f,r,"batch",I.reason,I.targetEndpoint,I.method,I.payload,{"Content-Type":"application/json"}),process.stderr.write(`\u26A0 TestRelic: Cloud upload failed, queued for retry.
1274
- `);}}else {let h=t?.queueDirectory??".testrelic/queue",g=e.getGitMetadata(),b=ue(),x=kr(e),T=le(n,x,g,b);oe(h,r,"batch",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs`,"POST",T,{"Content-Type":"application/json"});}await e.dispose();}catch{try{await e.dispose();}catch{}}}function Rr(e,t,r){if(t.length===0)return null;let n=basename(e,extname(e)).toLowerCase(),o=t.find(a=>basename(a,extname(a)).toLowerCase()===n);if(o)return o;let s=t.find(a=>basename(a).toLowerCase().includes(n));if(s)return s;let i=t.find(a=>{let l=basename(a,extname(a)).toLowerCase();return l.length>=3&&(n.startsWith(l)||n.includes(l))});if(i)return i;if(r){let a=basename(r,extname(r)).toLowerCase(),l=t.find(d=>basename(d,extname(d)).toLowerCase()===a);if(l)return l;let c=t.find(d=>basename(d).toLowerCase().includes(a));if(c)return c}return null}function Ys(e,t){if(t.length===0)return [];let r=basename(e,extname(e)).toLowerCase(),n=t.filter(o=>{let s=basename(o).toLowerCase(),i=basename(o,extname(o)).toLowerCase();return s.startsWith(r)||s.includes(r)?true:i.length>=3&&(r.startsWith(i)||r.includes(i))});return n.length>0?n:t.slice()}function Xs(e){for(let t of e)if(t.command==="startRecording"){let r=t.metadata,n=r?.path??r?.recording??r?.fileName;if(typeof n=="string")return n;if(typeof t.selector=="string")return t.selector}return null}function Sr(e){return basename(e).replace(/^commands[-_]?/i,"").replace(/\.json$/i,"").replace(/^\(/,"").replace(/\)$/,"").toLowerCase()}function Qs(e){let t=new Map;for(let[r,n]of e){let o=Sr(r),s=Xs(n);s&&o&&t.set(o,s);}return t}function Zs(e,t){let r=basename(t,extname(t)).toLowerCase();if(!r||e.size===0)return {commands:[],matchedAnyFile:false};let n=o=>Sr(o);for(let[o,s]of e)if(n(o)===r)return {commands:s,matchedAnyFile:true};for(let[o,s]of e){let i=n(o);if(i.length>=3&&i.includes(r))return {commands:s,matchedAnyFile:true}}for(let[o,s]of e){let i=n(o);if(i.length>=3&&r.includes(i))return {commands:s,matchedAnyFile:true}}return {commands:[],matchedAnyFile:false}}function ei(e){switch(e){case "android":return "Android";case "ios":return "iOS";case "web":return "Web";default:return}}function ti(e,t,r){let n=e.logEntries.length>0?e.logEntries.map(o=>({level:o.level.toLowerCase(),message:o.message,timestamp:o.timestamp,source:o.source})):void 0;return {testId:`${e.flowFile}::${e.flowName}`,title:e.flowName,status:e.status,duration:e.duration,suiteName:e.appId??"maestro-suite",filePath:e.flowFile,testType:"mobile",isFlaky:false,startedAt:e.startedAt,completedAt:e.completedAt,tags:e.tags,failure:e.failureMessage?{message:e.failureMessage}:null,retry:0,retryCount:0,retryStatus:null,source:"maestro",platform:e.platform!=="unknown"?e.platform:void 0,os:ei(e.platform),deviceName:e.deviceId,...n?{consoleLogs:n}:{},...t&&t.length>0?{apiCalls:t}:{},...r&&r.length>0?{actions:r}:{}}}function ri(e,t,r){if(e.length===0)return [];let n=Date.parse(t),o=Date.parse(r);return Number.isNaN(n)||Number.isNaN(o)?e.slice():e.filter(s=>{let i=Date.parse(s.timestamp);return Number.isNaN(i)?true:i>=n&&i<=o})}async function ni(e){let{config:t}=e,r=new Date().toISOString(),n=t.testRunId??randomUUID(),o=Ue(e.testOutputDir,e.debugOutputDir),s=e.junitPath??o.junitReportPath,i=e.debugOutputDir?Me(e.debugOutputDir):o.logPaths,a=[];for(let f of i){let m;try{let{statSync:v}=await import('fs');m=v(f).mtime;}catch{}let w=Ae(f,m);w.length>0&&a.push(...w);}let l=e.platform??"unknown";if(l==="unknown"&&a.length>0){let f=Ie(a);f!=="unknown"&&(l=f);}let c=new Map;if(e.flowsDir&&existsSync(e.flowsDir)){let f=Te(e.flowsDir);for(let m of f){let w=Se(m),v=w.name??m;c.set(v,w);}}let d=new Map,u=e.testOutputDir?Re(e.testOutputDir):o.commandJsonPaths;for(let f of u)d.set(f,Ce(f));let p=[],y=e.testOutputDir?Oe(e.testOutputDir):o.aiReportPaths;for(let f of y){let m=Ne(f);p.push(...m.defects);}let h=Qs(d),g=[];if(s&&existsSync(s)){let f=we(s),m=Array.from(d.values()).flat(),w=m.filter(S=>S.category==="assertion"),v=m.filter(S=>S.category!=="assertion");for(let S of f.testSuites)for(let k of S.testCases){let C=k.name,M=c.get(C),N=k.status==="SUCCESS"?"passed":k.status==="SKIPPED"?"skipped":"failed",F=k.time*1e3,L=k.classname||C,W=basename(L,extname(L)).toLowerCase(),Ar=h.get(W)??null,{commands:ct,matchedAnyFile:dt}=Zs(d,L),ut=dt?ct.filter(B=>B.category!=="assertion"):v,pt=dt?ct.filter(B=>B.category==="assertion"):w,ft=[...ut,...pt].reduce((B,Ir)=>{let ge=Date.parse(Ir.timestamp);return Number.isFinite(ge)&&ge<B?ge:B},Number.POSITIVE_INFINITY),fe=Number.isFinite(ft)?new Date(ft).toISOString():r,gt=new Date(new Date(fe).getTime()+F).toISOString();g.push({flowName:C,flowFile:L,appId:M?.appId??null,platform:l,deviceId:e.device,status:N,duration:F,startedAt:fe,completedAt:gt,tags:M?.tags??[],properties:M?.properties??{},commands:ut,assertions:pt,screenshotPaths:Ys(L,o.screenshotPaths),videoPath:Rr(L,o.videoPaths,Ar),aiDefects:p,logEntries:ri(a,fe,gt),failureMessage:k.failureMessage??k.errorMessage??null,failureType:k.failureType??k.errorType??null,subflowRefs:M?.subflowRefs??[],metadata:M??null});}}if(g.length===0&&c.size>0)for(let[,f]of c)g.push({flowName:f.name??f.filePath,flowFile:f.filePath,appId:f.appId,platform:l,deviceId:e.device,status:"passed",duration:0,startedAt:r,completedAt:r,tags:f.tags,properties:f.properties,commands:[],assertions:[],screenshotPaths:[],videoPath:null,aiDefects:[],logEntries:a.slice(),failureMessage:null,failureType:null,subflowRefs:f.subflowRefs,metadata:f});let b=(()=>{if(!t.network?.enabled&&!t.network?.harPath)return;let f=g.map(v=>({testId:`${v.flowFile}::${v.flowName}`,startedAt:v.startedAt,completedAt:v.completedAt})),m=dr(e.networkJsonlDir??null,t.network,f);if(m.size===0)return;let w=new Map;for(let[v,S]of m)w.set(v,ur(S));return w})(),x=$e(g,b),T=G(x),R=new Date().toISOString(),D=Date.now()-new Date(r).getTime(),I={schemaVersion:"1.0.0",testRunId:n,startedAt:r,completedAt:R,totalDuration:D,summary:T,ci:null,metadata:t.metadata??null,timeline:x,shardRunIds:null};if(mkdirSync(dirname(resolve(t.outputPath)),{recursive:true}),writeFileSync(resolve(t.outputPath),JSON.stringify(I,null,2),"utf-8"),ze(I,p,o.screenshotPaths,resolve(t.htmlReportPath)),qe(T,t.outputPath,t.htmlReportPath,t.quiet,p),t.openReport&&Ge(resolve(t.htmlReportPath)),t.cloud){let f=new J(t.cloud);await f.initialize();let m=t.includeVideo?o.videoPaths:[],w=[];if(m.length>0){for(let C of g){let M=basename(C.flowFile,extname(C.flowFile)).toLowerCase(),N=h.get(M)??null,F=Rr(C.flowFile,m,N);if(F){let L=`${C.flowFile}::${C.flowName}`;w.some(W=>W.path===F&&W.testId===L)||w.push({path:F,testId:L});}}if(m.length===1){let C=m[0];for(let M of g){let N=`${M.flowFile}::${M.flowName}`;w.some(F=>F.testId===N)||w.push({path:C,testId:N});}}}let v=new Set(w.map(C=>C.path)),S=m.filter(C=>!v.has(C)),k=g.map((C,M)=>{let N=`${C.flowFile}::${C.flowName}`,F=x[M]?.tests?.[0];return ti(C,b?.get(N),F?.actions??null)});await lt(f,t.cloud,n,I,R,D,T,t.includeScreenshots?o.screenshotPaths:[],S,k,w);}return {report:I,flowResults:g,aiDefects:p,artifacts:o}}function di(e){return "tests"in e&&"visitedAt"in e}function Tr(e){let t=[],r=[],n="",o="",s="";for(let c of e)try{let d=readFileSync(c,"utf-8"),u=JSON.parse(d);s||(s=u.testRunId),(!n||u.startedAt<n)&&(n=u.startedAt),(!o||u.completedAt&&u.completedAt>o)&&(o=u.completedAt);for(let p of u.timeline)t.push(p),di(p)&&r.push(p);}catch{process.stderr.write(`\u26A0 TestRelic: Unable to read report file: ${c}
1275
- `);}let i=G(r),a=n?new Date(n).getTime():Date.now(),l=o?new Date(o).getTime():Date.now();return {schemaVersion:"1.0.0",testRunId:s||`maestro-merged-${Date.now()}`,startedAt:n||new Date().toISOString(),completedAt:o||new Date().toISOString(),totalDuration:l-a,summary:i,ci:null,metadata:null,timeline:t,shardRunIds:null}}function ui(e,t){if(!existsSync(e))throw new Error(`Directory does not exist: ${e}`);let r=readdirSync(e).filter(o=>extname(o)===".json"&&o.includes("testrelic")).map(o=>join(e,o)),n=Tr(r);return writeFileSync(t,JSON.stringify(n,null,2),"utf-8"),n}export{J as CloudClient,me as DEFAULT_CLOUD_CONFIG,nr as buildMaestroArgs,G as buildSummary,$e as buildTimeline,Ut as buildTimelineEntry,le as buildUploadPayload,Mt as categorizeCommand,rt as cleanupExpiredQueue,Ue as collectArtifacts,Qe as collectGitMetadata,z as deriveNonGitProjectId,Ze as deriveRepoDisplayName,ue as detectCI,Ie as detectPlatformFromLogs,Oe as discoverAiReports,Re as discoverCommandFiles,ye as discoverConfigFile,Te as discoverFlowFiles,Me as discoverLogFiles,Ke as enforceHttps,te as exchangeToken,lt as finalizeAndUpload,Ss as finalizeRun,tt as flushQueue,ze as generateHtmlReport,Qn as getArtifactStats,ee as healthCheck,Rs as initRealtimeRun,re as isAuthError,xe as mergeCloudConfig,Tr as mergeReports,ui as mergeReportsFromDirectory,j as normalizeGitRemoteUrl,Ge as openInBrowser,ni as orchestrateReport,Ne as parseAiReportFile,Nt as parseAiReportHtml,Ce as parseCommandsFile,Et as parseCommandsJson,be as parseConfigFile,he as parseDuration,Se as parseFlowFile,_t as parseFlowYaml,we as parseJUnitFile,Ct as parseJUnitXml,Dt as parseLogContent,Ae as parseLogFile,qe as printConsoleSummary,gr as readPackageJsonName,Ye as refreshAccessToken,je as renderHtmlDocument,Jr as resolveConfig,K as resolveEnvVar,Y as resolveEnvVars,Xe as resolveRepo,No as runMaestro,vr as uploadArtifact,at as uploadArtifacts,ot as uploadBatchRun,oe as writeToQueue};//# sourceMappingURL=index.js.map
1274
+ `);}}else {let h=t?.queueDirectory??".testrelic/queue",g=e.getGitMetadata(),b=ue(),x=Cr(e),T=le(n,x,g,b);oe(h,r,"batch",e.getFailureReason()??"token_invalid",`${e.getEndpoint()}/runs`,"POST",T,{"Content-Type":"application/json"});}await e.dispose();}catch{try{await e.dispose();}catch{}}}function Sr(e,t,r){if(t.length===0)return null;let n=basename(e,extname(e)).toLowerCase(),o=t.find(a=>basename(a,extname(a)).toLowerCase()===n);if(o)return o;let s=t.find(a=>basename(a).toLowerCase().includes(n));if(s)return s;let i=t.find(a=>{let l=basename(a,extname(a)).toLowerCase();return l.length>=3&&(n.startsWith(l)||n.includes(l))});if(i)return i;if(r){let a=basename(r,extname(r)).toLowerCase(),l=t.find(d=>basename(d,extname(d)).toLowerCase()===a);if(l)return l;let c=t.find(d=>basename(d).toLowerCase().includes(a));if(c)return c}return null}function Xs(e,t){if(t.length===0)return [];let r=basename(e,extname(e)).toLowerCase(),n=t.filter(o=>{let s=basename(o).toLowerCase(),i=basename(o,extname(o)).toLowerCase();return s.startsWith(r)||s.includes(r)?true:i.length>=3&&(r.startsWith(i)||r.includes(i))});return n.length>0?n:t.slice()}function Qs(e){for(let t of e)if(t.command==="startRecording"){let r=t.metadata,n=r?.path??r?.recording??r?.fileName;if(typeof n=="string")return n;if(typeof t.selector=="string")return t.selector}return null}function Tr(e){return basename(e).replace(/^commands[-_]?/i,"").replace(/\.json$/i,"").replace(/^\(/,"").replace(/\)$/,"").toLowerCase()}function Zs(e){let t=new Map;for(let[r,n]of e){let o=Tr(r),s=Qs(n);s&&o&&t.set(o,s);}return t}function ei(e,t){let r=basename(t,extname(t)).toLowerCase();if(!r||e.size===0)return {commands:[],matchedAnyFile:false};let n=o=>Tr(o);for(let[o,s]of e)if(n(o)===r)return {commands:s,matchedAnyFile:true};for(let[o,s]of e){let i=n(o);if(i.length>=3&&i.includes(r))return {commands:s,matchedAnyFile:true}}for(let[o,s]of e){let i=n(o);if(i.length>=3&&r.includes(i))return {commands:s,matchedAnyFile:true}}return {commands:[],matchedAnyFile:false}}function ti(e){switch(e){case "android":return "Android";case "ios":return "iOS";case "web":return "Web";default:return}}function ri(e,t,r){let n=e.logEntries.length>0?e.logEntries.map(o=>({level:o.level.toLowerCase(),message:o.message,timestamp:o.timestamp,source:o.source})):void 0;return {testId:`${e.flowFile}::${e.flowName}`,title:e.flowName,status:e.status,duration:e.duration,suiteName:e.appId??"maestro-suite",filePath:e.flowFile,testType:"mobile",isFlaky:false,startedAt:e.startedAt,completedAt:e.completedAt,tags:e.tags,failure:e.failureMessage?{message:e.failureMessage}:null,retry:0,retryCount:0,retryStatus:null,source:"maestro",platform:e.platform!=="unknown"?e.platform:void 0,os:ti(e.platform),deviceName:e.deviceId,...n?{consoleLogs:n}:{},...t&&t.length>0?{apiCalls:t}:{},...r&&r.length>0?{actions:r}:{}}}function ni(e,t,r){if(e.length===0)return [];let n=Date.parse(t),o=Date.parse(r);return Number.isNaN(n)||Number.isNaN(o)?e.slice():e.filter(s=>{let i=Date.parse(s.timestamp);return Number.isNaN(i)?true:i>=n&&i<=o})}async function oi(e){let{config:t}=e,r=new Date().toISOString(),n=t.testRunId??randomUUID(),o=Ue(e.testOutputDir,e.debugOutputDir),s=e.junitPath??o.junitReportPath,i=e.debugOutputDir?Me(e.debugOutputDir):o.logPaths,a=[];for(let f of i){let m;try{let{statSync:v}=await import('fs');m=v(f).mtime;}catch{}let w=Ae(f,m);w.length>0&&a.push(...w);}let l=e.platform??"unknown";if(l==="unknown"&&a.length>0){let f=Ie(a);f!=="unknown"&&(l=f);}let c=new Map;if(e.flowsDir&&existsSync(e.flowsDir)){let f=Te(e.flowsDir);for(let m of f){let w=Se(m),v=w.name??m;c.set(v,w);}}let d=new Map,u=e.testOutputDir?Re(e.testOutputDir):o.commandJsonPaths;for(let f of u)d.set(f,Ce(f));let p=[],y=e.testOutputDir?Oe(e.testOutputDir):o.aiReportPaths;for(let f of y){let m=Ne(f);p.push(...m.defects);}let h=Zs(d),g=[];if(s&&existsSync(s)){let f=we(s),m=Array.from(d.values()).flat(),w=m.filter(S=>S.category==="assertion"),v=m.filter(S=>S.category!=="assertion");for(let S of f.testSuites)for(let k of S.testCases){let C=k.name,M=c.get(C),N=k.status==="SUCCESS"?"passed":k.status==="SKIPPED"?"skipped":"failed",F=k.time*1e3,L=k.classname||C,W=basename(L,extname(L)).toLowerCase(),Ir=h.get(W)??null,{commands:ct,matchedAnyFile:dt}=ei(d,L),ut=dt?ct.filter(B=>B.category!=="assertion"):v,pt=dt?ct.filter(B=>B.category==="assertion"):w,ft=[...ut,...pt].reduce((B,Mr)=>{let ge=Date.parse(Mr.timestamp);return Number.isFinite(ge)&&ge<B?ge:B},Number.POSITIVE_INFINITY),fe=Number.isFinite(ft)?new Date(ft).toISOString():r,gt=new Date(new Date(fe).getTime()+F).toISOString();g.push({flowName:C,flowFile:L,appId:M?.appId??null,platform:l,deviceId:e.device,status:N,duration:F,startedAt:fe,completedAt:gt,tags:M?.tags??[],properties:M?.properties??{},commands:ut,assertions:pt,screenshotPaths:Xs(L,o.screenshotPaths),videoPath:Sr(L,o.videoPaths,Ir),aiDefects:p,logEntries:ni(a,fe,gt),failureMessage:k.failureMessage??k.errorMessage??null,failureType:k.failureType??k.errorType??null,subflowRefs:M?.subflowRefs??[],metadata:M??null});}}if(g.length===0&&c.size>0)for(let[,f]of c)g.push({flowName:f.name??f.filePath,flowFile:f.filePath,appId:f.appId,platform:l,deviceId:e.device,status:"passed",duration:0,startedAt:r,completedAt:r,tags:f.tags,properties:f.properties,commands:[],assertions:[],screenshotPaths:[],videoPath:null,aiDefects:[],logEntries:a.slice(),failureMessage:null,failureType:null,subflowRefs:f.subflowRefs,metadata:f});let b=(()=>{if(!t.network?.enabled&&!t.network?.harPath)return;let f=g.map(v=>({testId:`${v.flowFile}::${v.flowName}`,startedAt:v.startedAt,completedAt:v.completedAt})),m=dr(e.networkJsonlDir??null,t.network,f);if(m.size===0)return;let w=new Map;for(let[v,S]of m)w.set(v,ur(S));return w})(),x=$e(g,b),T=G(x),R=new Date().toISOString(),D=Date.now()-new Date(r).getTime(),I={schemaVersion:"1.0.0",testRunId:n,startedAt:r,completedAt:R,totalDuration:D,summary:T,ci:null,metadata:t.metadata??null,timeline:x,shardRunIds:null};if(mkdirSync(dirname(resolve(t.outputPath)),{recursive:true}),writeFileSync(resolve(t.outputPath),JSON.stringify(I,null,2),"utf-8"),ze(I,p,o.screenshotPaths,resolve(t.htmlReportPath)),qe(T,t.outputPath,t.htmlReportPath,t.quiet,p),t.openReport&&Ge(resolve(t.htmlReportPath)),t.cloud){let f=new J(t.cloud);await f.initialize();let m=t.includeVideo?o.videoPaths:[],w=[];if(m.length>0){for(let C of g){let M=basename(C.flowFile,extname(C.flowFile)).toLowerCase(),N=h.get(M)??null,F=Sr(C.flowFile,m,N);if(F){let L=`${C.flowFile}::${C.flowName}`;w.some(W=>W.path===F&&W.testId===L)||w.push({path:F,testId:L});}}if(m.length===1){let C=m[0];for(let M of g){let N=`${M.flowFile}::${M.flowName}`;w.some(F=>F.testId===N)||w.push({path:C,testId:N});}}}let v=new Set(w.map(C=>C.path)),S=m.filter(C=>!v.has(C)),k=g.map((C,M)=>{let N=`${C.flowFile}::${C.flowName}`,F=x[M]?.tests?.[0];return ri(C,b?.get(N),F?.actions??null)});await lt(f,t.cloud,n,I,R,D,T,t.includeScreenshots?o.screenshotPaths:[],S,k,w);}return {report:I,flowResults:g,aiDefects:p,artifacts:o}}function ui(e){return "tests"in e&&"visitedAt"in e}function Ar(e){let t=[],r=[],n="",o="",s="";for(let c of e)try{let d=readFileSync(c,"utf-8"),u=JSON.parse(d);s||(s=u.testRunId),(!n||u.startedAt<n)&&(n=u.startedAt),(!o||u.completedAt&&u.completedAt>o)&&(o=u.completedAt);for(let p of u.timeline)t.push(p),ui(p)&&r.push(p);}catch{process.stderr.write(`\u26A0 TestRelic: Unable to read report file: ${c}
1275
+ `);}let i=G(r),a=n?new Date(n).getTime():Date.now(),l=o?new Date(o).getTime():Date.now();return {schemaVersion:"1.0.0",testRunId:s||`maestro-merged-${Date.now()}`,startedAt:n||new Date().toISOString(),completedAt:o||new Date().toISOString(),totalDuration:l-a,summary:i,ci:null,metadata:null,timeline:t,shardRunIds:null}}function pi(e,t){if(!existsSync(e))throw new Error(`Directory does not exist: ${e}`);let r=readdirSync(e).filter(o=>extname(o)===".json"&&o.includes("testrelic")).map(o=>join(e,o)),n=Ar(r);return writeFileSync(t,JSON.stringify(n,null,2),"utf-8"),n}export{J as CloudClient,me as DEFAULT_CLOUD_CONFIG,nr as buildMaestroArgs,G as buildSummary,$e as buildTimeline,Ut as buildTimelineEntry,le as buildUploadPayload,Mt as categorizeCommand,rt as cleanupExpiredQueue,Ue as collectArtifacts,Qe as collectGitMetadata,z as deriveNonGitProjectId,Ze as deriveRepoDisplayName,ue as detectCI,Ie as detectPlatformFromLogs,Oe as discoverAiReports,Re as discoverCommandFiles,ye as discoverConfigFile,Te as discoverFlowFiles,Me as discoverLogFiles,Ke as enforceHttps,te as exchangeToken,lt as finalizeAndUpload,Ts as finalizeRun,tt as flushQueue,ze as generateHtmlReport,Zn as getArtifactStats,ee as healthCheck,Ss as initRealtimeRun,re as isAuthError,xe as mergeCloudConfig,Ar as mergeReports,pi as mergeReportsFromDirectory,j as normalizeGitRemoteUrl,Ge as openInBrowser,oi as orchestrateReport,Ne as parseAiReportFile,Nt as parseAiReportHtml,Ce as parseCommandsFile,Et as parseCommandsJson,be as parseConfigFile,he as parseDuration,Se as parseFlowFile,_t as parseFlowYaml,we as parseJUnitFile,Ct as parseJUnitXml,Dt as parseLogContent,Ae as parseLogFile,qe as printConsoleSummary,gr as readPackageJsonName,Ye as refreshAccessToken,je as renderHtmlDocument,Wr as resolveConfig,K as resolveEnvVar,Y as resolveEnvVars,Xe as resolveRepo,Oo as runMaestro,kr as uploadArtifact,at as uploadArtifacts,ot as uploadBatchRun,oe as writeToQueue};//# sourceMappingURL=index.js.map
1276
1276
  //# sourceMappingURL=index.js.map