agent-device 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.15.0.apk → agent-device-android-snapshot-helper-0.15.1.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.15.1.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.15.0.manifest.json → agent-device-android-snapshot-helper-0.15.1.manifest.json} +6 -6
- package/dist/src/1393.js +1 -0
- package/dist/src/1769.js +7 -7
- package/dist/src/1974.js +2 -2
- package/dist/src/208.js +1 -1
- package/dist/src/2151.js +27 -22
- package/dist/src/221.js +3 -3
- package/dist/src/3572.js +1 -1
- package/dist/src/4829.js +1 -1
- package/dist/src/9542.js +2 -2
- package/dist/src/989.js +1 -1
- package/dist/src/android-adb.js +1 -1
- package/dist/src/cli.js +44 -44
- package/dist/src/index.d.ts +37 -5
- package/dist/src/internal/daemon.js +45 -45
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +155 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +3 -25
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +1 -14
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +3 -3
- package/ios-runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +7 -1
- package/package.json +6 -1
- package/server.json +2 -2
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.15.0.apk.sha256 +0 -1
- package/dist/src/840.js +0 -2
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
9d322b9af0fdcd0dd73e8c5123d29a30849d26b71e5b4adc077037f5bb0db987 agent-device-android-snapshot-helper-0.15.1.apk
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-snapshot-helper",
|
|
3
|
-
"version": "0.15.
|
|
4
|
-
"releaseTag": "v0.15.
|
|
5
|
-
"assetName": "agent-device-android-snapshot-helper-0.15.
|
|
3
|
+
"version": "0.15.1",
|
|
4
|
+
"releaseTag": "v0.15.1",
|
|
5
|
+
"assetName": "agent-device-android-snapshot-helper-0.15.1.apk",
|
|
6
6
|
"apkUrl": null,
|
|
7
|
-
"sha256": "
|
|
8
|
-
"checksumName": "agent-device-android-snapshot-helper-0.15.
|
|
7
|
+
"sha256": "9d322b9af0fdcd0dd73e8c5123d29a30849d26b71e5b4adc077037f5bb0db987",
|
|
8
|
+
"checksumName": "agent-device-android-snapshot-helper-0.15.1.apk.sha256",
|
|
9
9
|
"packageName": "com.callstack.agentdevice.snapshothelper",
|
|
10
|
-
"versionCode":
|
|
10
|
+
"versionCode": 15001,
|
|
11
11
|
"instrumentationRunner": "com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",
|
|
12
12
|
"minSdk": 23,
|
|
13
13
|
"targetSdk": 36,
|
package/dist/src/1393.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AppError as e}from"./9152.js";let r="user-installed";function t(e){return e??r}function o(r){if(void 0===r)throw new e("INVALID_ARGS","appsFilter must be resolved before executing the apps command");return r}export{r as DEFAULT_APPS_FILTER,o as assertResolvedAppsFilter,t as resolveAppsFilter};
|
package/dist/src/1769.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{promises as
|
|
2
|
-
${t.stderr}`}function W(t,e){return["-s",t,...e]}function $(t){return t.startsWith("emulator-")}function G(t){return t.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function K(t,e=u.android_boot.operationMs){return r("adb",W(t,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:e})}async function H(t,e){let a=e.replace(/_/g," ").trim();if(!$(t))return a||t;let i=await z(t);return i?i.replace(/_/g," "):a||t}async function j(t,e,a){try{return await a("adb",W(t,e),{allowFailure:!0,timeoutMs:1e4})}catch(t){var n;if("COMMAND_FAILED"===(n=i(t)).code&&"number"==typeof n.details?.timeoutMs)return;throw t}}async function z(t,e=r){for(let a of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let i=await j(t,["shell","getprop",a],e);if(!i)continue;let n=i.stdout.trim();if(0===i.exitCode&&n.length>0)return n}let a=await j(t,["emu","avd","name"],e);if(!a)return;let i=function(t){let e=t.split("\n").map(t=>t.trim()).filter(t=>t.length>0);if(0!==e.length)return"OK"===e.at(-1)&&e.pop(),e.join("\n").trim()||void 0}(a.stdout);if(0===a.exitCode&&i)return i}async function q(t,e){let a=V(await r("adb",W(t,["shell","cmd","package","has-feature",e]),{allowFailure:!0,timeoutMs:u.android_boot.operationMs})).toLowerCase();return!!a.includes("true")||!a.includes("false")&&null}async function Z(t){return(await B(F,2,async e=>await q(t,e))).some(t=>!0===t)}async function J(t){var e;let a;return"tv"===((a=V(await r("adb",W(t,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:u.android_boot.operationMs})).toLowerCase()).includes("tv")||a.includes("leanback")?"tv":null)||await Z(t)?"tv":(e=V(await r("adb",W(t,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:u.android_boot.operationMs})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(e))?"tv":"mobile"}async function X(t={}){if(await p(),!await l("adb"))throw new n("TOOL_MISSING","adb not found in PATH");let e=t.serialAllowlist??x(void 0),a=(await Q()).filter(t=>!e||e.has(t.serial));return await B(a,3,async({serial:t,rawModel:e})=>{let[a,i,n]=await Promise.all([H(t,e),ta(t),J(t)]);return{platform:"android",id:t,name:a,kind:$(t)?"emulator":"device",target:n,booted:i}})}async function Q(){return(await r("adb",["devices","-l"],{timeoutMs:u.android_boot.operationMs})).stdout.split("\n").map(t=>t.trim()).filter(t=>t.length>0&&!t.startsWith("List of devices")).map(t=>t.split(/\s+/)).filter(t=>"device"===t[1]).map(t=>({serial:t[0],rawModel:(t.find(t=>t.startsWith("model:"))??"").replace("model:","")}))}async function Y(){let t=await r("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:u.android_boot.operationMs});if(0!==t.exitCode)throw new n("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return t.stdout.split("\n").map(t=>t.trim()).filter(t=>t.length>0)}async function tt(t){let e=Date.now();for(;Date.now()-e<t.timeoutMs;){try{let e=await te(t.avdName,t.serial);if(e)return{platform:"android",id:e,name:t.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await m(1e3)}throw new n("COMMAND_FAILED","Android emulator did not appear in time",{avdName:t.avdName,serial:t.serial,timeoutMs:t.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function te(t,e){let a=G(t);for(let t of(await Q()).filter(t=>(!e||t.serial===e)&&$(t.serial)))if(G(t.rawModel)===a||G(await H(t.serial,t.rawModel))===a)return t.serial}async function ta(t){try{let e=await K(t);return"1"===e.stdout.trim()}catch{return!1}}async function ti(t){var e,a;let i;await p();let r=t.avdName.trim();if(!r)throw new n("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let o=t.timeoutMs??12e4;if(!await l("adb"))throw new n("TOOL_MISSING","adb not found in PATH");if(!await l("emulator"))throw new n("TOOL_MISSING","emulator not found in PATH");let d=await Y(),u=function(t,e){let a=t.find(t=>t===e);if(a)return a;let i=G(e);return t.find(t=>G(t)===i)}(d,r);if(!u)throw new n("DEVICE_NOT_FOUND",`No Android emulator AVD named ${t.avdName}`,{requestedAvdName:r,availableAvds:d,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let c=Date.now(),f=(e=await X(),a=t.serial,i=G(u),e.find(t=>"android"===t.platform&&"emulator"===t.kind&&(!a||t.id===a)&&G(t.name)===i));if(!f){let e=["-avd",u];t.headless&&e.push("-no-window","-no-audio"),s("emulator",e)}let m=f??await tt({avdName:u,serial:t.serial,timeoutMs:o}),w=Math.max(1e3,o-(Date.now()-c));await tn(m.id,w);let h=(await X()).find(t=>t.id===m.id);return h?{...h,name:u,booted:!0}:{...m,name:u,booted:!0}}async function tn(t,e=6e4){let a,r=c.fromTimeoutMs(e),o=Math.max(1,Math.ceil(e/1e3)),l=!1;try{await d(async({deadline:i})=>{if(i?.isExpired())throw l=!0,new n("COMMAND_FAILED","Android boot deadline exceeded",{serial:t,timeoutMs:e,elapsedMs:r.elapsedMs(),message:"timeout"});let o=Math.max(1e3,i?.remainingMs()??e),s=await K(t,Math.min(o,u.android_boot.operationMs));if(a=s,"1"!==s.stdout.trim())throw new n("COMMAND_FAILED","Android device is still booting",{serial:t,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:o,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:t=>{let e=P({error:t,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==e&&"ANDROID_BOOT_TIMEOUT"!==e}},{deadline:r,phase:"boot",classifyReason:t=>P({error:t,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}})})}catch(f){let o=i(f),s=a?.stdout,d=a?.stderr,u=a?.exitCode,c=P({error:f,stdout:s,stderr:d,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===c&&"Android device is still booting"===o.message&&(c="ANDROID_BOOT_TIMEOUT");let p={serial:t,timeoutMs:e,elapsedMs:r.elapsedMs(),reason:c,hint:U(c),stdout:s,stderr:d,exitCode:u};if(l||"ANDROID_BOOT_TIMEOUT"===c)throw new n("COMMAND_FAILED","Android device did not finish booting in time",p);if("TOOL_MISSING"===o.code)throw new n("TOOL_MISSING",o.message,{...p,...o.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===c)throw new n("COMMAND_FAILED",o.message,{...p,...o.details??{}});throw new n(o.code,o.message,{...p,...o.details??{}},o.cause)}}async function tr(t,e,a){return await h(t)(e,a)}function to(t){return{platform:"android",id:t,name:t,kind:t.startsWith("emulator-")?"emulator":"device",booted:!0}}async function tl(){if(await p(),!await l("adb"))throw new n("TOOL_MISSING","adb not found in PATH")}let ts=/\.(?:apk|aab)$/i,td=/^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$/;function tu(t){var e,a;let i=t.trim();return 0===i.length?"other":ts.test(i)?i.includes("/")||i.includes("\\")||i.startsWith(".")||i.startsWith("~")||(e=i,!td.test(e))?"binary":"package":(a=i,td.test(a))?"package":"other"}function tc(t){return`Android runtime hints require an installed package name, not "${t}". Install or reinstall the app first, then relaunch by package.`}async function tp(t,e){let i="url"===t.kind&&_(t.url),n=await g({source:t,isInstallablePath:(t,e)=>{var i;let n;return e.isFile()&&(i=t,".apk"===(n=a.extname(i).toLowerCase())||".aab"===n)},installableLabel:"Android installable (.apk or .aab)",allowArchiveExtraction:"url"!==t.kind||i,signal:e?.signal});try{let t=e?.resolveIdentity===!1?{}:await tf(n.installablePath);return{archivePath:n.archivePath,installablePath:n.installablePath,packageName:t.packageName,cleanup:n.cleanup}}catch(t){throw await n.cleanup(),t}}async function tf(t){let e=a.extname(t).toLowerCase();return".apk"!==e&&".aab"!==e?{}:{packageName:await f(t)}}let tm={settings:{type:"intent",value:"android.settings.SETTINGS"}},tw="android.intent.category.LAUNCHER",th="android.intent.category.LEANBACK_LAUNCHER",tA="android.intent.category.DEFAULT",tg="Run agent-device apps --platform android to discover the installed package name, then retry open with that exact package.",t_=C();function tb(t){return{platform:"android",deviceId:t.id,variant:t.target??""}}async function ty(t,e){let a=e.trim();if("package"===tu(a))return{type:"package",value:a};let i=tm[a.toLowerCase()];if(i)return i;let r=tb(t),o=t_.get(r,a);if(o)return o;let l=(await tr(t,["shell","pm","list","packages"])).stdout.split("\n").map(t=>t.replace("package:","").trim()).filter(Boolean).filter(t=>t.toLowerCase().includes(a.toLowerCase()));if(1===l.length)return t_.set(r,a,{type:"package",value:l[0]});if(l.length>1)throw new n("INVALID_ARGS",`Multiple packages matched "${e}"`,{matches:l,hint:"Run agent-device apps --platform android to see the exact installed package names before retrying open."});throw new n("APP_NOT_INSTALLED",`No package found matching "${e}"`,{hint:tg})}async function tv(t,e){let a=await tI(t);return("user-installed"===e?(await tM(t)).filter(t=>a.has(t)):Array.from(a)).sort((t,e)=>t.localeCompare(e)).map(t=>({package:t,name:tN(t)}))}async function tI(t){let e=new Set;for(let a of tO(t,{includeFallbackWhenUnknown:!0})){let i=await tr(t,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",a],{allowFailure:!0});if(0===i.exitCode&&0!==i.stdout.trim().length)for(let t of y(i.stdout))e.add(t)}return e}function tO(t,e={}){return"tv"===t.target?[th]:"mobile"===t.target?[tw]:e.includeFallbackWhenUnknown?[tw,th]:[tw]}async function tM(t){return v((await tr(t,["shell","pm","list","packages","-3"])).stdout)}function tN(t){let e=new Set(["com","android","google","app","apps","service","services","mobile","client"]),a=t.split(".").flatMap(t=>t.split(/[_-]+/)).map(t=>t.trim().toLowerCase()).filter(t=>t.length>0),i=a[a.length-1]??t;for(let t=a.length-1;t>=0;t-=1){let n=a[t];if(!e.has(n)){i=n;break}}return i.split(/[^a-z0-9]+/i).filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}async function tC(t){let e=await tk(t,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(e)return e;let a=await tk(t,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return a||{}}async function tk(t,e){for(let a of e){let e=I((await tr(t,a,{allowFailure:!0})).stdout??"");if(e)return e}return null}async function tE(t,e,a){t.booted||await tn(t.id);let i=e.trim();if(M(i)){if(a)throw new n("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await tr(t,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",i]);return}let r=await ty(t,e),o=tO(t)[0]??tw;if("intent"===r.type){if(a)throw new n("INVALID_ARGS","Activity override requires a package name, not an intent");await tr(t,["shell","am","start","-W","-a",r.value]);return}if(a){let e=a.includes("/")?a:`${r.value}/${a.startsWith(".")?a:`.${a}`}`;try{await tr(t,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",tA,"-c",o,"-n",e])}catch(e){throw await tL(t,r.value,e),e}return}let l=await tr(t,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",tA,"-c",o,"-p",r.value],{allowFailure:!0});if(0===l.exitCode&&!tx(l.stdout,l.stderr))return;let s=await tR(t,r.value);if(!s){if(!await tD(t,r.value))throw tT(r.value);throw new n("COMMAND_FAILED",`Failed to launch ${r.value}`,{stdout:l.stdout,stderr:l.stderr})}await tr(t,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",tA,"-c",o,"-n",s])}function tT(t){return new n("APP_NOT_INSTALLED",`No package found matching "${t}"`,{package:t,hint:tg})}async function tD(t,e){let a=await tr(t,["shell","pm","path",e],{allowFailure:!0}),i=`${a.stdout}
|
|
3
|
-
${a.stderr}`;return!!(0===a.exitCode&&/\bpackage:/i.test(
|
|
4
|
-
${String(a.details?.stderr??"")}`:"")||!await
|
|
5
|
-
${
|
|
6
|
-
${
|
|
7
|
-
${r}`.toLowerCase()).includes("no shell command implementation")||o.includes("unknown command"))throw new
|
|
1
|
+
import{promises as e}from"node:fs";import t from"node:os";import a from"node:path";import{asAppError as n,AppError as i}from"./9152.js";import{emitDiagnostic as r}from"./7599.js";import{runCmd as o,resolveFileOverridePath as s,whichCmd as l,runCmdDetached as d}from"./9818.js";import{ensureAndroidSdkPathConfigured as u,resolveAndroidArchivePackageName as c}from"./7651.js";import{sleep as p}from"./4829.js";import{resolveAndroidAdbProvider as f,resolveAndroidAdbExecutor as m,installAndroidAdbPackage as w}from"./9639.js";import{materializeInstallablePath as h,isTrustedInstallSourceUrl as A}from"./989.js";function y(e){let t=new Set;for(let a of e.split("\n")){let e=a.trim();if(!e)continue;let n=e.split(/\s+/)[0];if(!n.includes("/"))continue;let i=n.split("/")[0];i.includes(".")&&i&&t.add(i)}return Array.from(t)}function g(e){return e.split("\n").map(e=>{let t=e.trim();return t.startsWith("package:")?t.slice(8):t}).filter(Boolean)}function b(e){let t=e.split("\n");for(let e of["mCurrentFocus=Window{","mFocusedApp=AppWindowToken{","mResumedActivity:","ResumedActivity:"])for(let a of t){let t=a.indexOf(e);if(-1===t)continue;let n=function(e){for(let t of e.trim().split(/\s+/)){let e=t.indexOf("/");if(e<=0)continue;let a=v(t.slice(0,e),!1),n=v(t.slice(e+1),!0);if(a&&n&&a.length===e)return{package:a,activity:n}}return null}(a.slice(t+e.length));if(n)return n}return null}function v(e,t){let a=0;for(;a<e.length&&function(e,t){if(!e)return!1;let a=e.charCodeAt(0);return a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122||"_"===e||"."===e||t&&"$"===e}(e[a],t);)a+=1;return e.slice(0,a)}function M(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let a=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!a)return!1;let n=a[1]?.toLowerCase(),i=a[2]??"";return"http"!==n&&"https"!==n&&"ws"!==n&&"wss"!==n&&"ftp"!==n&&"ftps"!==n||i.startsWith("//")}function _(e,t){let a,n=e?.trim();return n?n:"http"===(a=t.trim().split(":")[0]?.toLowerCase())||"https"===a?"com.apple.mobilesafari":void 0}function I(e={}){let t=e.ttlMs??3e4,a=e.nowMs??Date.now,n=new Map,i=e=>{var t;let a=[(t=e).platform,t.deviceId,""].join("\0");for(let e of n.keys())e.startsWith(a)&&n.delete(e)};return{get(e,t){let i=N(e,t),r=n.get(i);if(r)return r.expiresAtMs<=a()?void n.delete(i):r.value},set:(e,i,r)=>(n.set(N(e,i),{value:r,expiresAtMs:a()+t}),r),clear(e){i(e)},async invalidateWhile(e,t){i(e);try{return await t()}finally{i(e)}}}}function N(e,t){return[e.platform,e.deviceId,e.variant??"",t.trim().toLowerCase()].join("\0")}function O(e){return["1","true","yes","on"].includes((e??"").trim().toLowerCase())}class C{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new C(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function k(e,t={},a={}){let n,r={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=r.maxAttempts;t+=1){if(a.signal?.aborted)throw new i("COMMAND_FAILED","request canceled",{reason:"request_canceled"});if(a.deadline?.isExpired()&&t>1)break;try{let n=await e({attempt:t,maxAttempts:r.maxAttempts,deadline:a.deadline});return a.onEvent?.({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),T({phase:a.phase,event:"succeeded",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs()}),n}catch(d){n=d;let e=a.classifyReason?.(d),i={phase:a.phase,event:"attempt_failed",attempt:t,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};if(a.onEvent?.(i),T(i),t>=r.maxAttempts||r.shouldRetry&&!r.shouldRetry(d,t))break;let o=function(e,t,a,n){let i=Math.min(t,e*2**(n-1));return Math.max(0,i+i*a*(2*Math.random()-1))}(r.baseDelayMs,r.maxDelayMs,r.jitter,t),s=a.deadline?Math.min(o,a.deadline.remainingMs()):o;if(s<=0)break;let l={phase:a.phase,event:"retry_scheduled",attempt:t,maxAttempts:r.maxAttempts,delayMs:s,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:e};a.onEvent?.(l),T(l),await function(e,t){return new Promise(a=>{if(t?.aborted)return void a();let n=!1,i=()=>{n||(n=!0,t&&t.removeEventListener("abort",o),a())},r=setTimeout(i,e);function o(){clearTimeout(r),i()}t&&t.addEventListener("abort",o,{once:!0})})}(s,a.signal)}}let o={phase:a.phase,event:"exhausted",attempt:r.maxAttempts,maxAttempts:r.maxAttempts,elapsedMs:a.deadline?.elapsedMs(),remainingMs:a.deadline?.remainingMs(),reason:a.classifyReason?.(n)};if(a.onEvent?.(o),T(o),n)throw n;throw new i("COMMAND_FAILED","retry failed")}async function D(e,t={}){return k(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function T(e){r({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}})}function E(e){return e?.trim()||void 0}function x(e){return E(e)}function L(e){return new Set(e.split(/[\s,]+/).map(e=>e.trim()).filter(Boolean))}function S(e,t=process.env){let a=E(e)??E(t.AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST);if(a)return L(a)}function R(e){let t=e.error?n(e.error):null,a=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===a?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let r=t?.details??{},o="string"==typeof r.message?r.message:void 0,s="string"==typeof r.stdout?r.stdout:void 0,l="string"==typeof r.stderr?r.stderr:void 0,d=r.boot&&"object"==typeof r.boot?r.boot:null,u=r.bootstatus&&"object"==typeof r.bootstatus?r.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,o,s,l,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0,"string"==typeof u?.stdout?u.stdout:void 0,"string"==typeof u?.stderr?u.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===a&&(c.includes("runner did not accept connection")||"connect"===i&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===a&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===a&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function P(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI reduce parallel jobs or use a larger runner.";case"IOS_RUNNER_CONNECT_TIMEOUT":return"Retry runner startup, inspect xcodebuild logs, and verify simulator responsiveness before command execution.";case"ANDROID_BOOT_TIMEOUT":return"Retry emulator startup and verify sys.boot_completed reaches 1; consider increasing startup budget in CI.";case"ADB_TRANSPORT_UNAVAILABLE":return"Check adb server/device transport (adb devices -l), restart adb, and ensure the target device is online and authorized.";case"CI_RESOURCE_STARVATION_SUSPECTED":return"CI machine may be resource constrained; reduce parallel jobs or use a larger runner.";case"IOS_TOOL_MISSING":return"Xcode command-line tools are missing or not in PATH; run xcode-select --install and verify xcrun works.";case"BOOT_COMMAND_FAILED":return"Inspect command stderr/stdout for the failing boot phase and retry after environment validation.";default:return"Retry once and inspect verbose logs for the failing phase."}}let F=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];async function U(e,t,a){let n=Array(e.length),i=0,r=Math.min(t,e.length);return await Promise.all(Array.from({length:r},async()=>{for(;i<e.length;){let t=i;i+=1,n[t]=await a(e[t])}})),n}function B(e){return`${e.stdout}
|
|
2
|
+
${e.stderr}`}function W(e,t){return["-s",e,...t]}function $(e){return e.startsWith("emulator-")}function V(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function G(e,t=1e4){return o("adb",W(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function K(e,t){let a=t.replace(/_/g," ").trim();if(!$(e))return a||e;let n=await H(e);return n?n.replace(/_/g," "):a||e}async function j(e,t,a){try{return await a("adb",W(e,t),{allowFailure:!0,timeoutMs:1e4})}catch(e){var i;if("COMMAND_FAILED"===(i=n(e)).code&&"number"==typeof i.details?.timeoutMs)return;throw e}}async function H(e,t=o){for(let a of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let n=await j(e,["shell","getprop",a],t);if(!n)continue;let i=n.stdout.trim();if(0===n.exitCode&&i.length>0)return i}let a=await j(e,["emu","avd","name"],t);if(!a)return;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0);if(0!==t.length)return"OK"===t.at(-1)&&t.pop(),t.join("\n").trim()||void 0}(a.stdout);if(0===a.exitCode&&n)return n}async function z(e,t){let a=B(await o("adb",W(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase();return!!a.includes("true")||!a.includes("false")&&null}async function q(e){return(await U(F,2,async t=>await z(e,t))).some(e=>!0===e)}async function Z(e){var t;let a;return"tv"===((a=B(await o("adb",W(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:1e4})).toLowerCase()).includes("tv")||a.includes("leanback")?"tv":null)||await q(e)?"tv":(t=B(await o("adb",W(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:1e4})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function J(e={}){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??S(void 0),a=(await X()).filter(e=>!t||t.has(e.serial));return await U(a,3,async({serial:e,rawModel:t})=>{let[a,n,i]=await Promise.all([K(e,t),et(e),Z(e)]);return{platform:"android",id:e,name:a,kind:$(e)?"emulator":"device",target:i,booted:n}})}async function X(){return(await o("adb",["devices","-l"],{timeoutMs:1e4})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}))}async function Q(){let e=await o("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:1e4});if(0!==e.exitCode)throw new i("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function Y(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await ee(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await p(1e3)}throw new i("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function ee(e,t){let a=V(e);for(let e of(await X()).filter(e=>(!t||e.serial===t)&&$(e.serial)))if(V(e.rawModel)===a||V(await K(e.serial,e.rawModel))===a)return e.serial}async function et(e){try{let t=await G(e);return"1"===t.stdout.trim()}catch{return!1}}async function ea(e){var t,a;let n;await u();let r=e.avdName.trim();if(!r)throw new i("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let o=e.timeoutMs??12e4;if(!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH");if(!await l("emulator"))throw new i("TOOL_MISSING","emulator not found in PATH");let s=await Q(),c=function(e,t){let a=e.find(e=>e===t);if(a)return a;let n=V(t);return e.find(e=>V(e)===n)}(s,r);if(!c)throw new i("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:r,availableAvds:s,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let p=Date.now(),f=(t=await J(),a=e.serial,n=V(c),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!a||e.id===a)&&V(e.name)===n));if(!f){let t=["-avd",c];e.headless&&t.push("-no-window","-no-audio"),d("emulator",t)}let m=f??await Y({avdName:c,serial:e.serial,timeoutMs:o}),w=Math.max(1e3,o-(Date.now()-p));await en(m.id,w);let h=(await J()).find(e=>e.id===m.id);return h?{...h,name:c,booted:!0}:{...m,name:c,booted:!0}}async function en(e,t=6e4){let a,r=C.fromTimeoutMs(t),o=Math.max(1,Math.ceil(t/1e3)),s=!1;try{await k(async({deadline:n})=>{if(n?.isExpired())throw s=!0,new i("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),l=await G(e,Math.min(o,1e4));if(a=l,"1"!==l.stdout.trim())throw new i("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:l.stdout,stderr:l.stderr,exitCode:l.exitCode})},{maxAttempts:o,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=R({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:r,phase:"boot",classifyReason:e=>R({error:e,stdout:a?.stdout,stderr:a?.stderr,context:{platform:"android",phase:"boot"}})})}catch(f){let o=n(f),l=a?.stdout,d=a?.stderr,u=a?.exitCode,c=R({error:f,stdout:l,stderr:d,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===c&&"Android device is still booting"===o.message&&(c="ANDROID_BOOT_TIMEOUT");let p={serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),reason:c,hint:P(c),stdout:l,stderr:d,exitCode:u};if(s||"ANDROID_BOOT_TIMEOUT"===c)throw new i("COMMAND_FAILED","Android device did not finish booting in time",p);if("TOOL_MISSING"===o.code)throw new i("TOOL_MISSING",o.message,{...p,...o.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===c)throw new i("COMMAND_FAILED",o.message,{...p,...o.details??{}});throw new i(o.code,o.message,{...p,...o.details??{}},o.cause)}}async function ei(e,t,a){return await m(e)(t,a)}function er(e){return{platform:"android",id:e,name:e,kind:e.startsWith("emulator-")?"emulator":"device",booted:!0}}async function eo(){if(await u(),!await l("adb"))throw new i("TOOL_MISSING","adb not found in PATH")}let es=/\.(?:apk|aab)$/i,el=/^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$/;function ed(e){var t,a;let n=e.trim();return 0===n.length?"other":es.test(n)?n.includes("/")||n.includes("\\")||n.startsWith(".")||n.startsWith("~")||(t=n,!el.test(t))?"binary":"package":(a=n,el.test(a))?"package":"other"}function eu(e){return`Android runtime hints require an installed package name, not "${e}". Install or reinstall the app first, then relaunch by package.`}async function ec(e,t){let n="url"===e.kind&&A(e.url),i=await h({source:e,isInstallablePath:(e,t)=>{var n;let i;return t.isFile()&&(n=e,".apk"===(i=a.extname(n).toLowerCase())||".aab"===i)},installableLabel:"Android installable (.apk or .aab)",allowArchiveExtraction:"url"!==e.kind||n,signal:t?.signal});try{let e=t?.resolveIdentity===!1?{}:await ep(i.installablePath);return{archivePath:i.archivePath,installablePath:i.installablePath,packageName:e.packageName,cleanup:i.cleanup}}catch(e){throw await i.cleanup(),e}}async function ep(e){let t=a.extname(e).toLowerCase();return".apk"!==t&&".aab"!==t?{}:{packageName:await c(e)}}let ef={settings:{type:"intent",value:"android.settings.SETTINGS"}},em="android.intent.category.LAUNCHER",ew="android.intent.category.LEANBACK_LAUNCHER",eh="android.intent.category.DEFAULT",eA="Run agent-device apps --platform android to discover the installed package name, then retry open with that exact package.",ey=I();function eg(e){return{platform:"android",deviceId:e.id,variant:e.target??""}}async function eb(e,t){let a=t.trim();if("package"===ed(a))return{type:"package",value:a};let n=ef[a.toLowerCase()];if(n)return n;let r=eg(e),o=ey.get(r,a);if(o)return o;let s=(await ei(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(a.toLowerCase()));if(1===s.length)return ey.set(r,a,{type:"package",value:s[0]});if(s.length>1)throw new i("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:s,hint:"Run agent-device apps --platform android to see the exact installed package names before retrying open."});throw new i("APP_NOT_INSTALLED",`No package found matching "${t}"`,{hint:eA})}async function ev(e,t){let a=await eM(e);return("user-installed"===t?(await eI(e)).filter(e=>a.has(e)):Array.from(a)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:eN(e)}))}async function eM(e){let t=new Set;for(let a of e_(e,{includeFallbackWhenUnknown:!0})){let n=await ei(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",a],{allowFailure:!0});if(0===n.exitCode&&0!==n.stdout.trim().length)for(let e of y(n.stdout))t.add(e)}return t}function e_(e,t={}){return"tv"===e.target?[ew]:"mobile"===e.target?[em]:t.includeFallbackWhenUnknown?[em,ew]:[em]}async function eI(e){return g((await ei(e,["shell","pm","list","packages","-3"])).stdout)}function eN(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),a=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),n=a[a.length-1]??e;for(let e=a.length-1;e>=0;e-=1){let i=a[e];if(!t.has(i)){n=i;break}}return n.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function eO(e){let t=await eC(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let a=await eC(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return a||{}}async function eC(e,t){for(let a of t){let t=b((await ei(e,a,{allowFailure:!0})).stdout??"");if(t)return t}return null}async function ek(e,t,a){e.booted||await en(e.id);let n=t.trim();if(M(n)){if(a)throw new i("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await ei(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",n]);return}let r=await eb(e,t),o=e_(e)[0]??em;if("intent"===r.type){if(a)throw new i("INVALID_ARGS","Activity override requires a package name, not an intent");await ei(e,["shell","am","start","-W","-a",r.value]);return}if(a){let t=a.includes("/")?a:`${r.value}/${a.startsWith(".")?a:`.${a}`}`;try{await ei(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eh,"-c",o,"-n",t])}catch(t){throw await eE(e,r.value,t),t}return}let s=await ei(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eh,"-c",o,"-p",r.value],{allowFailure:!0});if(0===s.exitCode&&!eS(s.stdout,s.stderr))return;let l=await eL(e,r.value);if(!l){if(!await eT(e,r.value))throw eD(r.value);throw new i("COMMAND_FAILED",`Failed to launch ${r.value}`,{stdout:s.stdout,stderr:s.stderr})}await ei(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eh,"-c",o,"-n",l])}function eD(e){return new i("APP_NOT_INSTALLED",`No package found matching "${e}"`,{package:e,hint:eA})}async function eT(e,t){let a=await ei(e,["shell","pm","path",t],{allowFailure:!0}),n=`${a.stdout}
|
|
3
|
+
${a.stderr}`;return!!(0===a.exitCode&&/\bpackage:/i.test(n))||(ex(n),!1)}async function eE(e,t,a){if(ex(a instanceof i?`${String(a.details?.stdout??"")}
|
|
4
|
+
${String(a.details?.stderr??"")}`:"")||!await eT(e,t))throw eD(t)}function ex(e){return/\bunknown package\b/i.test(e)||/\bpackage .* (?:was|is) not found\b/i.test(e)||/\bpackage .* does not exist\b/i.test(e)||/\bcould not find package\b/i.test(e)}async function eL(e,t){for(let a of Array.from(new Set(e_(e,{includeFallbackWhenUnknown:!0})))){let n=await ei(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",a,t],{allowFailure:!0});if(0!==n.exitCode)continue;let i=eR(n.stdout);if(i)return i}return null}function eS(e,t){let a=`${e}
|
|
5
|
+
${t}`;return/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)}function eR(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let a=t[e];if(a.includes("/"))return a.split(/\s+/)[0]}return null}async function eP(e){e.booted||await en(e.id)}async function eF(e,t){if("settings"===t.trim().toLowerCase())return void await ei(e,["shell","am","force-stop","com.android.settings"]);let a=await eb(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","Close requires a package name, not an intent");await ei(e,["shell","am","force-stop",a.value])}async function eU(e,t){let a=await eb(e,t);if("intent"===a.type)throw new i("INVALID_ARGS","App uninstall requires a package name, not an intent");let n=await ei(e,["uninstall",a.value],{allowFailure:!0});if(0!==n.exitCode){let e=`${n.stdout}
|
|
6
|
+
${n.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new i("COMMAND_FAILED",`adb uninstall failed for ${a.value}`,{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})}return{package:a.value}}let eB=null;async function eW(){let e=`${process.env.PATH??""}::${process.env.AGENT_DEVICE_BUNDLETOOL_JAR??""}`;if(eB?.key===e)return eB.invocation;if(await l("bundletool")){let t={cmd:"bundletool",prefixArgs:[]};return eB={key:e,invocation:t},t}let t=await s(process.env.AGENT_DEVICE_BUNDLETOOL_JAR,"AGENT_DEVICE_BUNDLETOOL_JAR");if(!t)throw new i("TOOL_MISSING","bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR to a bundletool-all.jar path.");let a={cmd:"java",prefixArgs:["-jar",t]};return eB={key:e,invocation:a},a}async function e$(e){let t=await eW();await o(t.cmd,[...t.prefixArgs,...e])}async function eV(n,i){let r=f(n),o="universal";if(r.installBundle)return void await r.installBundle(i,{mode:o});let s=await e.mkdtemp(a.join(t.tmpdir(),"agent-device-aab-")),l=a.join(s,"bundle.apks");try{await e$(["build-apks","--bundle",i,"--output",l,"--mode",o]),await e$(["install-apks","--apks",l,"--device-id",n.id])}finally{await e.rm(s,{recursive:!0,force:!0})}}async function eG(e,t){".aab"===a.extname(t).toLowerCase()?await eV(e,t):await w(t,{device:e,replace:!0})}async function eK(e){return new Set((await ei(e,["shell","pm","list","packages"])).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean))}async function ej(e,t){let a=Array.from(await eK(e)).filter(e=>!t.has(e));if(1===a.length)return a[0]}async function eH(e,t){await ey.invalidateWhile(eg(e),async()=>{e.booted||await en(e.id),await eG(e,t)})}async function ez(e,t,a){let n=a?void 0:await eK(e);return await eH(e,t),a??(n?await ej(e,n):void 0)}async function eq(e,t){e.booted||await en(e.id);let a=await ec({kind:"path",path:t});try{let t=await ez(e,a.installablePath,a.packageName),n=t?eN(t):void 0;return{archivePath:a.archivePath,installablePath:a.installablePath,packageName:t,appName:n,launchTarget:t}}finally{await a.cleanup()}}async function eZ(e,t,a){return await ey.invalidateWhile(eg(e),async()=>{e.booted||await en(e.id);let{package:n}=await eU(e,t),i=await ec({kind:"path",path:a},{resolveIdentity:!1});try{await eH(e,i.installablePath)}finally{await i.cleanup()}return{package:n}})}async function eJ(e,t={}){let a=["logcat","-d","-v","time"];void 0!==t.lines&&a.push("-t",String(Math.max(1,Math.floor(t.lines))));let n=await e(a,{allowFailure:!0,timeoutMs:t.timeoutMs,signal:t.signal});if(0!==n.exitCode)throw new i("COMMAND_FAILED","Failed to capture Android logcat",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode});return n.stdout}function eX(e,t={}){if(!e.spawn)throw new i("UNSUPPORTED_OPERATION","Android ADB provider does not support streams",{capability:"adb.spawn"});let a=["logcat","-v","time"];t.pid&&a.push("--pid",t.pid);let n=e.spawn(a,{stdio:["ignore","pipe","pipe"],signal:t.signal});return t.output&&n.stdout&&n.stdout.pipe(t.output,{end:!1}),n}let eQ=new Set(["com.google.android.inputmethod.latin","com.samsung.android.honeyboard","com.touchtype.swiftkey","com.microsoft.swiftkey"]);function eY(e){let t=e1(e.packageName),a=(e.resourceId??"").toLowerCase(),n=e1(e.activeInputMethodPackage);if(t&&n&&t===n)return{inputMethodOwned:!0,source:"active-input-method"};if(n&&a.startsWith(`${n}:id/`))return{inputMethodOwned:!0,source:"active-input-method-resource"};if(t&&eQ.has(t))return{inputMethodOwned:!0,source:"known-ime-package"};for(let e of eQ)if(a.startsWith(`${e}:id/`))return{inputMethodOwned:!0,source:"known-ime-resource"};return{inputMethodOwned:!1,source:"app"}}function e0(e){return eY(e).inputMethodOwned}function e1(e){return(e??"").trim().toLowerCase()||void 0}async function e2(e){return await e4(m(e))}async function e4(e){let t=await e(["shell","dumpsys","input_method"],{allowFailure:!0});if(0!==t.exitCode)throw new i("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t,a=function(e){let t=new Map;for(let a of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=a[1],n=a[2]?.toLowerCase();e&&("true"===n||"false"===n)&&t.set(e,"true"===n)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),n=a??!1;if(null===a){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(n=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),o=i.length>0?i[i.length-1]?.[1]:void 0,s=o?`0x${o.toLowerCase()}`:void 0,l=e8(e,/\bpackageName=([A-Za-z0-9_.]+)\b/g),d=e8(e,/\b(?:resourceId|resource-id)=([^\s,}]+)/g),u=function(e){for(let t of[/\bmCurMethodId=([^\s]+)/i,/\bmCurId=([^\s]+)/i,/\bmCurrentInputMethodId=([^\s]+)/i,/\bcurMethodId=([^\s]+)/i]){let a=e.match(t),n=function(e){let t=(e??"").trim();if(!t)return;let a=(t.split("/")[0]??"").match(/[a-zA-Z0-9_.]+/);return e1(a?.[0])}(a?.[1]);if(n)return n}}(e),c=function(e,t,a){return e||t?eY({packageName:e,resourceId:t,activeInputMethodPackage:a}).inputMethodOwned?"ime":"app":"unknown"}(l,d,u);return!u&&((t=e1(l))&&eQ.has(t)||function(e){let t=(e??"").toLowerCase();for(let e of eQ)if(t.startsWith(`${e}:id/`))return!0;return!1}(d))&&r({level:"warn",phase:"android_input_ownership_fallback",data:{focusedPackage:l,focusedResourceId:d}}),{visible:n,inputType:s,type:s?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let a=15&t;if(2===a)return"number";if(3===a)return"phone";if(4===a)return"datetime";if(1!==a)return"unknown";let n=4080&t;return 32===n||208===n?"email":128===n||224===n||144===n?"password":"text"}(s):void 0,inputMethodPackage:u,focusedPackage:l,focusedResourceId:d,inputOwner:c}}(t.stdout)}async function e9(e){return await e3(m(e))}async function e3(e){let t=await e4(e),a=t,n=0;for(;a.visible&&n<2;)await e(["shell","input","keyevent","111"]),n+=1,await p(120),a=await e4(e);if(t.visible&&a.visible)throw new i("UNSUPPORTED_OPERATION","Android keyboard dismiss is unavailable for the current IME without back navigation.",{attempts:n,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner});return{attempts:n,wasVisible:t.visible,dismissed:t.visible&&!a.visible,visible:a.visible,inputType:a.inputType,type:a.type,inputMethodPackage:a.inputMethodPackage,focusedPackage:a.focusedPackage,focusedResourceId:a.focusedResourceId,inputOwner:a.inputOwner}}function e8(e,t){let a;for(let n of e.matchAll(t))a=n[1];return a}async function e5(e){return await e6(m(e))}async function e6(e){let t,a;return(a=(t=(await tt(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?a[1]??"":"null"===t.trim().toLowerCase()?"":t}async function e7(e,t){await te(m(e),t)}async function te(e,t){await tt(e,["shell","cmd","clipboard","set","text",t],"write")}async function tt(e,t,a){var n,r;let o,s=await e(t,{allowFailure:!0});if(n=s.stdout,r=s.stderr,(o=`${n}
|
|
7
|
+
${r}`.toLowerCase()).includes("no shell command implementation")||o.includes("unknown command"))throw new i("UNSUPPORTED_OPERATION",`Android shell clipboard ${a} is not supported on this device.`);if(0!==s.exitCode)throw new i("COMMAND_FAILED",`Failed to ${a} Android clipboard text`,{stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode});return s.stdout}export{C as Deadline,er as androidDeviceForSerial,P as bootFailureHint,eJ as captureAndroidLogcatWithAdb,ed as classifyAndroidAppTarget,R as classifyBootFailure,eF as closeAndroidApp,I as createAppResolutionCache,e9 as dismissAndroidKeyboard,e3 as dismissAndroidKeyboardWithAdb,eo as ensureAdb,ea as ensureAndroidEmulatorBooted,eu as formatAndroidInstalledPackageRequiredMessage,eO as getAndroidAppState,e2 as getAndroidKeyboardState,e4 as getAndroidKeyboardStatusWithAdb,eN as inferAndroidAppName,eq as installAndroidApp,ez as installAndroidInstallablePathAndResolvePackageName,eS as isAmStartError,e0 as isAndroidInputMethodOwnedNode,M as isDeepLinkTarget,O as isEnvTruthy,ev as listAndroidApps,J as listAndroidDevices,ek as openAndroidApp,eP as openAndroidDevice,b as parseAndroidForegroundApp,eR as parseAndroidLaunchComponent,y as parseAndroidLaunchablePackages,g as parseAndroidUserInstalledPackages,L as parseSerialAllowlist,ec as prepareAndroidInstallArtifact,e5 as readAndroidClipboardText,e6 as readAndroidClipboardWithAdb,eZ as reinstallAndroidApp,eb as resolveAndroidApp,S as resolveAndroidSerialAllowlist,_ as resolveIosDeviceDeepLinkBundleId,x as resolveIosSimulatorDeviceSetPath,k as retryWithPolicy,ei as runAndroidAdb,eX as streamAndroidLogcatWithAdb,en as waitForAndroidBoot,D as withRetry,e7 as writeAndroidClipboardText,te as writeAndroidClipboardWithAdb};
|
package/dist/src/1974.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"node:fs";import
|
|
2
|
-
`,"utf8")}function j(r){try{let t=e.readdirSync(r);0===t.length&&e.rmdirSync(r)}catch{}}function C(t,n){let i=r.dirname(t.statePath),o=r.dirname(t.logPath);var a=t.statePath;try{e.unlinkSync(a)}catch{}var s=t.logPath;try{e.unlinkSync(s)}catch{}j(i),o!==i&&j(o),r.basename(i)===n.slug&&j(r.dirname(i))}function B(e,r){return e.includes(r.runArg)}function K(e){return A(e.consumerKey)??A(e.profileKey)??null}function D(e,r){return!r||e.consumers.includes(r)?e:{...e,consumers:[...e.consumers,r]}}async function H(e,r){if(!u(e.pid))return;let t=a(e.pid);if(t&&B(t,r)){try{process.kill(e.pid,"SIGTERM")}catch(r){let e=r.code;if("ESRCH"===e||"EPERM"===e)return;throw r}if(!await s(e.pid,1e3)){try{process.kill(e.pid,"SIGKILL")}catch(r){let e=r.code;if("ESRCH"===e||"EPERM"===e)return;throw r}await s(e.pid,1e3)}}}async function O(t){var o;let s,l=K(t),S=R(t.projectRoot,t.definition,t.profileKey,t.stateDir),w=x(S.statePath);if(w&&function(e,r){var t,n;if(!u(e.pid))return!1;if(e.startTime){let r=c(e.pid);if(!r||r!==e.startTime)return!1}let i=a(e.pid);return!!i&&!!B(i,r.definition)&&!!e.bridgeScope&&e.serverBaseUrl===d(r.serverBaseUrl)&&e.localBaseUrl===d(r.localBaseUrl)&&e.launchUrl===A(r.launchUrl)&&e.registerPath===A(r.registerPath)&&e.unregisterPath===A(r.unregisterPath)&&e.devicePort===r.devicePort&&e.session===A(r.session)&&(t=e.bridgeScope,n=r.bridgeScope,t.tenantId===n.tenantId&&t.runId===n.runId&&t.leaseId===n.leaseId)&&e.tokenHash===$(r.bearerToken)}(w,t)){let e=D(w,l);return e!==w&&T(S.statePath,e),{pid:w.pid,spawned:!1,statePath:S.statePath,logPath:S.logPath}}w&&(await H(w,t.definition),C(S,t.definition)),o=S.statePath,e.mkdirSync(r.dirname(o),{recursive:!0}),e.closeSync(e.openSync(o,"a"));try{s=function(t,o){let s=function(t){let i=n(import.meta.url),o=r.extname(i)||".js",a=[r.join(r.dirname(i),`${N}${o}`),r.join(r.dirname(i),"internal",`${N}${o}`)].find(r=>e.existsSync(r));if(!a)throw Error(`${t.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return a}(t.definition),l=s.endsWith(".ts")?["--experimental-strip-types"]:[];e.mkdirSync(r.dirname(o),{recursive:!0});let u=e.openSync(o,"a"),S=0;try{let e;S=i(process.execPath,[...l,s,t.definition.runArg],{env:((e={...t.env??process.env})[p]=d(t.serverBaseUrl),e[m]=t.bearerToken,e[_]=d(t.localBaseUrl),e[f]=R(t.projectRoot,t.definition,t.profileKey,t.stateDir).statePath,e[y]=t.bridgeScope.tenantId,e[v]=t.bridgeScope.runId,e[g]=t.bridgeScope.leaseId,t.launchUrl?.trim()?e[h]=t.launchUrl.trim():delete e[h],t.registerPath?.trim()?e[U]=t.registerPath.trim():delete e[U],t.unregisterPath?.trim()?e[I]=t.unregisterPath.trim():delete e[I],void 0!==t.devicePort?e[b]=String(t.devicePort):delete e[b],t.session?.trim()?e[P]=t.session.trim():delete e[P],e),stdio:["ignore",u,u]})}finally{e.closeSync(u)}if(!Number.isInteger(S)||S<=0)throw Error(`Failed to start ${t.definition.displayName} process.`);return{pid:S,startTime:c(S)??void 0,command:a(S)??void 0,serverBaseUrl:d(t.serverBaseUrl),localBaseUrl:d(t.localBaseUrl),launchUrl:A(t.launchUrl),registerPath:A(t.registerPath),unregisterPath:A(t.unregisterPath),devicePort:t.devicePort,session:A(t.session),bridgeScope:t.bridgeScope,tokenHash:$(t.bearerToken),consumers:[]}}(t,S.logPath),T(S.statePath,D(s,l))}catch(e){throw s&&await H(s,t.definition).catch(()=>{}),C(S,t.definition),e}return{pid:s.pid,spawned:!0,statePath:S.statePath,logPath:S.logPath}}async function L(e){let r=K(e),t=R(e.projectRoot,e.definition,e.profileKey,e.stateDir),n=x(t.statePath);if(!n)return C(t,e.definition),{stopped:!1,statePath:t.statePath};let i=r?{...n,consumers:n.consumers.filter(e=>e!==r)}:{...n,consumers:[]};return i.consumers.length>0?(T(t.statePath,i),{stopped:!1,statePath:t.statePath}):(await H(n,e.definition),C(t,e.definition),{stopped:!0,statePath:t.statePath})}let G={slug:"metro-companion",runArg:w,displayName:"Metro companion"};async function J(e){return await O({...e,definition:G,registerPath:e.registerPath??"/api/metro/companion/register"})}async function F(e){return await L({...e,definition:G})}function V(e){return"string"==typeof e&&e.trim()?d(e.trim()):""}function q(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function W(e,r,t){return M(e,{env:r,cwd:t})}function z(r){try{return e.accessSync(r,e.constants.F_OK),!0}catch{return!1}}function X(e,r,t){if(null==e||""===e)return r;let n=Number.parseInt(String(e),10);return Number.isInteger(n)?Math.max(n,t):r}function Y(e,r){if(null==e||""===e)return r;let t=Number.parseInt(String(e),10);if(!Number.isInteger(t)||t<1||t>65535)throw new E("INVALID_ARGS",`Invalid Metro port: ${String(e)}. Use 1-65535.`);return t}function Q(e,r){return{platform:r,bundleUrl:S(e,r)}}function Z(e,r){return{platform:r,metroHost:q(e?.metro_host),metroPort:e?.metro_port,bundleUrl:q(e?.metro_bundle_url),launchUrl:q(e?.launch_url)}}async function ee(e){await k(e)}async function er(e,r,t={}){try{let n=await fetch(e,{headers:t,signal:AbortSignal.timeout(r)});return{ok:n.ok,status:n.status,body:await n.text()}}catch(t){if(t instanceof Error&&"TimeoutError"===t.name)throw Error(`Timed out fetching ${e} after ${r}ms`);throw t}}async function et(e,r){try{let t=await er(e,r);return t.ok&&t.body.includes("packager-status:running")}catch{return!1}}async function en(e){if(Number.isInteger(e)&&!(e<=0)){try{process.kill(e,"SIGTERM")}catch(r){let e=r.code;if("ESRCH"===e||"EPERM"===e)return;throw r}if(!await s(e,1e3)){try{process.kill(e,"SIGKILL")}catch(r){let e=r.code;if("ESRCH"===e||"EPERM"===e)return;throw r}await s(e,1e3)}}}function ei(e,r){let t=Error(e);return t.retryable=r,t}function eo(e,r){return!!(e>=500||408===e||425===e||429===e||JSON.stringify(r).includes("Metro companion is not connected"))}function ea(e){return!!(e&&"object"==typeof e&&"retryable"in e&&!0===e.retryable)}async function es(e){let r;try{var t,n;r=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:"POST",headers:(t=e.baseUrl,n=e.bearerToken,{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...t.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(r){if(r instanceof Error&&"TimeoutError"===r.name)throw ei(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0);throw ei(r instanceof Error?r.message:String(r),!0)}let i=function(e,r,t){if(!e)return{};try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw Error("Expected a JSON object");return r}catch(o){let n=e.slice(0,200),i=o instanceof Error?o.message:String(o);throw ei(`/api/metro/bridge returned invalid JSON (${r}) from ${t}: ${i}. body=${JSON.stringify(n)}`,eo(r,e))}}(await r.text(),r.status,e.baseUrl);if(!r.ok)throw ei(`/api/metro/bridge failed (${r.status}): ${JSON.stringify(i)}`,eo(r.status,i));var o=i;let a=o.data??o;if(!a||"object"!=typeof a||Array.isArray(a))throw ei("/api/metro/bridge returned malformed descriptor: Expected a JSON object.",!1);try{return{enabled:a.enabled,baseUrl:a.base_url,statusUrl:a.status_url??"",bundleUrl:a.bundle_url??"",iosRuntime:Z(a.ios_runtime,"ios"),androidRuntime:Z(a.android_runtime,"android"),upstream:{bundleUrl:a.upstream.bundle_url??"",host:a.upstream.host??"",port:a.upstream.port??0,statusUrl:a.upstream.status_url??""},probe:{reachable:a.probe.reachable,statusCode:a.probe.status_code,latencyMs:a.probe.latency_ms,detail:a.probe.detail}}}catch(e){throw ei(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function el(e,r,t,n,i){let o=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return r&&o.push(`bridgeError=${r}`),t?.probe.reachable===!1&&o.push(`bridgeProbe=${t.probe.detail||`unreachable (status ${t.probe.statusCode||0})`}`),n&&n!==r&&o.push(`initialBridgeError=${n}`),i&&o.push(`metroCompanionLog=${i}`),o.join(" ")}async function eu(e,r,t){let n=Date.now()+r;for(;Date.now()<n;){let r=Math.min(t,Math.max(n-Date.now(),1));if(await et(e,r))return!0;let i=Math.min(500,Math.max(n-Date.now(),0));i>0&&await ee(i)}return!1}async function ec(e){let r=Date.now()+e.startupTimeoutMs,t=null,n=null;for(;Date.now()<r;){try{let r=await es({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(!1!==r.probe.reachable)return r;t=r,n=null}catch(e){if(n=e instanceof Error?e.message:String(e),!ea(e))break}let i=Math.min(1e3,Math.max(r-Date.now(),0));i>0&&await ee(i)}throw Error(el(e.baseUrl,n,t,e.initialBridgeError,e.companionLogPath))}async function ed(t={}){let n=t.env??process.env,a=process.cwd(),s=W(t.projectRoot??a,n,a),l=function(t,n){if("auto"!==n)return n;let i=function(t){let n=r.join(t,"package.json");if(!z(n))throw new E("INVALID_ARGS",`package.json not found at ${n}`);return JSON.parse(e.readFileSync(n,"utf8"))}(t);return"string"==typeof({...i.dependencies??{},...i.devDependencies??{}}).expo?"expo":"react-native"}(s,t.kind??"auto"),u=Y(t.metroPort??8081,8081),c=q(t.listenHost)??"0.0.0.0",d=q(t.statusHost)??"127.0.0.1",m=V(t.publicBaseUrl),p=X(t.startupTimeoutMs,18e4,3e4),f=X(t.probeTimeoutMs,1e4,1e3),h=t.reuseExisting??!0,g=t.installDependenciesIfNeeded??!0,y=t.runtimeFilePath?W(t.runtimeFilePath,n,a):null,b=W(t.logPath??r.join(s,".agent-device","metro.log"),n,a);if(!m&&!V(t.proxyBaseUrl))throw new E("INVALID_ARGS","metro prepare requires --public-base-url <url>.");let{proxyEnabled:S,proxyBaseUrl:w,proxyBearerToken:P}=function(e,r){if(e&&!r)throw new E("INVALID_ARGS","metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_PROXY_TOKEN.");if(!e&&r)throw new E("INVALID_ARGS","metro prepare requires --proxy-base-url when proxy auth is provided.");return{proxyEnabled:!!(e&&r),proxyBaseUrl:e,proxyBearerToken:r}}(V(t.proxyBaseUrl),q(t.proxyBearerToken)??""),v=S?function(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new E("INVALID_ARGS","metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.");return e}(t.bridgeScope):null,U=g?function(t,n){if(function(r){try{return e.statSync(r).isDirectory()}catch{return!1}}(r.join(t,"node_modules")))return{installed:!1};let i=z(r.join(t,"pnpm-lock.yaml"))?{command:"pnpm",installArgs:["install"]}:z(r.join(t,"yarn.lock"))?{command:"yarn",installArgs:["install"]}:{command:"npm",installArgs:["install"]};return o(i.command,i.installArgs,{cwd:t,env:n}),{installed:!0,packageManager:i.command}}(s,n):{installed:!1},_=`http://${d}:${u}/status`,I=!1,M=!1,k=0;if(h&&await et(_,f))M=!0;else if(I=!0,k=function(t,n,o,a,s,l){let u="expo"===n?{command:"npx",installArgs:["expo","start","--host","lan","--port",String(o)]}:{command:"npx",installArgs:["react-native","start","--host",a,"--port",String(o)]};e.mkdirSync(r.dirname(s),{recursive:!0});let c=e.openSync(s,"a"),d=0;try{d=i(u.command,u.installArgs,{cwd:t,env:l,stdio:["ignore",c,c]})}finally{e.closeSync(c)}if(!Number.isInteger(d)||d<=0)throw Error("Failed to start Metro. Expected a detached child PID.");return{pid:d}}(s,l,u,c,b,n).pid,!await eu(_,p,f))throw await en(k).catch(()=>{}),Error(`Metro did not become ready at ${_} within ${p}ms. Check ${b}.`);let N=m?Q(m,"ios"):{platform:"ios"},$=m?Q(m,"android"):{platform:"android"},A=null,R=null;if(v)try{A=await es({baseUrl:w,bearerToken:P,scope:v,timeoutMs:f})}catch(e){if(!ea(e))throw e;R=e instanceof Error?e.message:String(e)}if(v&&(!A||!1===A.probe.reachable)){let e;try{e=(await J({projectRoot:s,serverBaseUrl:w,bearerToken:P,bridgeScope:v,localBaseUrl:`http://${d}:${u}`,launchUrl:q(t.launchUrl),profileKey:q(t.companionProfileKey),consumerKey:q(t.companionConsumerKey),env:n})).logPath}catch(e){throw Error(el(w,e instanceof Error?e.message:String(e),A,R))}try{A=await ec({baseUrl:w,bearerToken:P,scope:v,probeTimeoutMs:f,startupTimeoutMs:p,initialBridgeError:R,companionLogPath:e})}catch(e){throw e instanceof Error?e:Error(String(e))}}v&&function(e,r){if(!r?.iosRuntime.bundleUrl)throw Error(el(e,"bridge descriptor is missing ios_runtime.metro_bundle_url",r))}(w,A);let x=A?.iosRuntime??N,T=A?.androidRuntime??$,j={projectRoot:s,kind:l,dependenciesInstalled:U.installed,packageManager:U.packageManager??null,started:I,reused:M,pid:k,logPath:b,statusUrl:_,runtimeFilePath:y,iosRuntime:x,androidRuntime:T,bridge:A};return y&&(e.mkdirSync(r.dirname(y),{recursive:!0}),e.writeFileSync(y,JSON.stringify(j,null,2))),j}async function em(e={}){let r=X(e.timeoutMs,1e4,1e3),t=function(e){var r;let t,n=q(e.bundleUrl)??e.runtime?.bundleUrl,i=!!q(e.bundleUrl),o=!!q(n),a=l({metroHost:q(e.metroHost)??(i?void 0:q(e.runtime?.metroHost))??(o?void 0:"localhost"),metroPort:void 0!==e.metroPort?Y(e.metroPort,8081):i?void 0:e.runtime?.metroPort??(o?void 0:8081),bundleUrl:n});if(!a)throw new E("INVALID_ARGS","Unable to resolve Metro host and port for reload.");return r=function(e){let r=q(e);if(!r)return"/reload";let t=new URL(r).pathname.replace(/\/+$/,"");return t.endsWith("/index.bundle")?`${t.slice(0,-13)}/reload`:"/reload"}(n),(t=new URL(`${a.scheme}://localhost`)).hostname=a.host,t.port=String(a.port),t.pathname=r,t.toString()}(e),n=await er(t,r);if(!n.ok)throw new E("COMMAND_FAILED",`Metro reload failed (${n.status}).`,{reloadUrl:t,status:n.status,body:n.body,hint:"Verify Metro is running and the target React Native app is connected to this Metro instance."});return{reloaded:!0,reloadUrl:t,status:n.status,body:n.body}}export{Q as buildMetroRuntimeHints,O as ensureCompanionTunnel,J as ensureMetroCompanion,ed as prepareMetroRuntime,em as reloadMetro,L as stopCompanionTunnel,F as stopMetroCompanion};
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{createHash as r}from"node:crypto";import{fileURLToPath as n}from"node:url";import{runCmdDetached as o,runCmdSync as i}from"./9818.js";import{readProcessCommand as a,waitForProcessExit as s,resolveRuntimeTransportHints as l,isProcessAlive as u,readProcessStartTime as c}from"./8656.js";import{normalizeBaseUrl as d,ENV_COMPANION_TUNNEL_BEARER_TOKEN as p,ENV_COMPANION_TUNNEL_SERVER_BASE_URL as m,ENV_COMPANION_TUNNEL_STATE_PATH as h,ENV_COMPANION_TUNNEL_LAUNCH_URL as f,ENV_COMPANION_TUNNEL_SCOPE_LEASE_ID as g,ENV_COMPANION_TUNNEL_SCOPE_TENANT_ID as y,ENV_COMPANION_TUNNEL_DEVICE_PORT as b,buildBundleUrl as P,METRO_COMPANION_RUN_ARG as S,ENV_COMPANION_TUNNEL_SESSION as w,ENV_COMPANION_TUNNEL_SCOPE_RUN_ID as E,ENV_COMPANION_TUNNEL_REGISTER_PATH as _,ENV_COMPANION_TUNNEL_LOCAL_BASE_URL as v,ENV_COMPANION_TUNNEL_UNREGISTER_PATH as U}from"./2301.js";import{AppError as M}from"./9152.js";import{resolveUserPath as I}from"./3267.js";import{sleep as k}from"./4829.js";let T="companion-tunnel";function A(e){return r("sha256").update(e).digest("hex")}function N(e){return e?.trim()?e.trim():void 0}function R(e,r,n,o){let i=o??t.join(e,".agent-device");if(!n)return{statePath:t.join(i,`${r.slug}.json`),logPath:t.join(i,`${r.slug}.log`)};let a=A(n).slice(0,12),s=t.join(i,r.slug);return{statePath:t.join(s,`${r.slug}-${a}.json`),logPath:t.join(s,`${r.slug}-${a}.log`)}}function $(t){try{let r=JSON.parse(e.readFileSync(t,"utf8"));if(!Number.isInteger(r.pid)||0>=Number(r.pid)||"string"!=typeof r.serverBaseUrl||"string"!=typeof r.localBaseUrl||"string"!=typeof r.tokenHash||0===r.tokenHash.length)return null;let n=Array.isArray(r.consumers)?r.consumers.filter(e=>"string"==typeof e&&e.length>0):[];return{pid:Number(r.pid),startTime:"string"==typeof r.startTime?r.startTime:void 0,command:"string"==typeof r.command?r.command:void 0,serverBaseUrl:r.serverBaseUrl,localBaseUrl:r.localBaseUrl,launchUrl:N("string"==typeof r.launchUrl?r.launchUrl:void 0),registerPath:N("string"==typeof r.registerPath?r.registerPath:void 0),unregisterPath:N("string"==typeof r.unregisterPath?r.unregisterPath:void 0),devicePort:Number.isInteger(r.devicePort)?Number(r.devicePort):void 0,session:N("string"==typeof r.session?r.session:void 0),bridgeScope:function(e){if(!(!e||"object"!=typeof e||Array.isArray(e))&&"string"==typeof e.tenantId&&"string"==typeof e.runId&&"string"==typeof e.leaseId)return{tenantId:e.tenantId,runId:e.runId,leaseId:e.leaseId}}(r.bridgeScope),tokenHash:r.tokenHash,consumers:n}}catch{return null}}function x(r,n){e.mkdirSync(t.dirname(r),{recursive:!0}),e.writeFileSync(r,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,"utf8")}function j(t){try{let r=e.readdirSync(t);0===r.length&&e.rmdirSync(t)}catch{}}function B(r,n){let o=t.dirname(r.statePath),i=t.dirname(r.logPath);var a=r.statePath;try{e.unlinkSync(a)}catch{}var s=r.logPath;try{e.unlinkSync(s)}catch{}j(o),i!==o&&j(i),t.basename(o)===n.slug&&j(t.dirname(o))}function C(e,t){return e.includes(t.runArg)}function D(e){return N(e.consumerKey)??N(e.profileKey)??null}function H(e,t){return!t||e.consumers.includes(t)?e:{...e,consumers:[...e.consumers,t]}}async function K(e,t){if(!u(e.pid))return;let r=a(e.pid);if(r&&C(r,t)){try{process.kill(e.pid,"SIGTERM")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}if(!await s(e.pid,1e3)){try{process.kill(e.pid,"SIGKILL")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}await s(e.pid,1e3)}}}async function O(r){var i;let s,l=D(r),P=R(r.projectRoot,r.definition,r.profileKey,r.stateDir),S=$(P.statePath);if(S&&function(e,t){var r,n;if(!u(e.pid))return!1;if(e.startTime){let t=c(e.pid);if(!t||t!==e.startTime)return!1}let o=a(e.pid);return!!o&&!!C(o,t.definition)&&!!e.bridgeScope&&e.serverBaseUrl===d(t.serverBaseUrl)&&e.localBaseUrl===d(t.localBaseUrl)&&e.launchUrl===N(t.launchUrl)&&e.registerPath===N(t.registerPath)&&e.unregisterPath===N(t.unregisterPath)&&e.devicePort===t.devicePort&&e.session===N(t.session)&&(r=e.bridgeScope,n=t.bridgeScope,r.tenantId===n.tenantId&&r.runId===n.runId&&r.leaseId===n.leaseId)&&e.tokenHash===A(t.bearerToken)}(S,r)){let e=H(S,l);return e!==S&&x(P.statePath,e),{pid:S.pid,spawned:!1,statePath:P.statePath,logPath:P.logPath}}S&&(await K(S,r.definition),B(P,r.definition)),i=P.statePath,e.mkdirSync(t.dirname(i),{recursive:!0}),e.closeSync(e.openSync(i,"a"));try{s=function(r,i){let s=function(r){let o=n(import.meta.url),i=t.extname(o)||".js",a=[t.join(t.dirname(o),`${T}${i}`),t.join(t.dirname(o),"internal",`${T}${i}`)].find(t=>e.existsSync(t));if(!a)throw Error(`${r.displayName} entrypoint not found. Rebuild the package to include the companion worker entry.`);return a}(r.definition),l=s.endsWith(".ts")?["--experimental-strip-types"]:[];e.mkdirSync(t.dirname(i),{recursive:!0});let u=e.openSync(i,"a"),P=0;try{let e;P=o(process.execPath,[...l,s,r.definition.runArg],{env:((e={...r.env??process.env})[m]=d(r.serverBaseUrl),e[p]=r.bearerToken,e[v]=d(r.localBaseUrl),e[h]=R(r.projectRoot,r.definition,r.profileKey,r.stateDir).statePath,e[y]=r.bridgeScope.tenantId,e[E]=r.bridgeScope.runId,e[g]=r.bridgeScope.leaseId,r.launchUrl?.trim()?e[f]=r.launchUrl.trim():delete e[f],r.registerPath?.trim()?e[_]=r.registerPath.trim():delete e[_],r.unregisterPath?.trim()?e[U]=r.unregisterPath.trim():delete e[U],void 0!==r.devicePort?e[b]=String(r.devicePort):delete e[b],r.session?.trim()?e[w]=r.session.trim():delete e[w],e),stdio:["ignore",u,u]})}finally{e.closeSync(u)}if(!Number.isInteger(P)||P<=0)throw Error(`Failed to start ${r.definition.displayName} process.`);return{pid:P,startTime:c(P)??void 0,command:a(P)??void 0,serverBaseUrl:d(r.serverBaseUrl),localBaseUrl:d(r.localBaseUrl),launchUrl:N(r.launchUrl),registerPath:N(r.registerPath),unregisterPath:N(r.unregisterPath),devicePort:r.devicePort,session:N(r.session),bridgeScope:r.bridgeScope,tokenHash:A(r.bearerToken),consumers:[]}}(r,P.logPath),x(P.statePath,H(s,l))}catch(e){throw s&&await K(s,r.definition).catch(()=>{}),B(P,r.definition),e}return{pid:s.pid,spawned:!0,statePath:P.statePath,logPath:P.logPath}}async function L(e){let t=D(e),r=R(e.projectRoot,e.definition,e.profileKey,e.stateDir),n=$(r.statePath);if(!n)return B(r,e.definition),{stopped:!1,statePath:r.statePath};let o=t?{...n,consumers:n.consumers.filter(e=>e!==t)}:{...n,consumers:[]};return o.consumers.length>0?(x(r.statePath,o),{stopped:!1,statePath:r.statePath}):(await K(n,e.definition),B(r,e.definition),{stopped:!0,statePath:r.statePath})}let G={slug:"metro-companion",runArg:S,displayName:"Metro companion"};async function F(e){return await O({...e,definition:G,registerPath:e.registerPath??"/api/metro/companion/register"})}async function J(e){return await L({...e,definition:G})}function V(e){return"string"==typeof e&&e.trim()?d(e.trim()):""}function q(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function W(e,t,r){return I(e,{env:t,cwd:r})}function z(t){try{return e.accessSync(t,e.constants.F_OK),!0}catch{return!1}}function Q(e,t,r){if(null==e||""===e)return t;let n=Number.parseInt(String(e),10);return Number.isInteger(n)?Math.max(n,r):t}function X(e,t){if(null==e||""===e)return t;let r=Number.parseInt(String(e),10);if(!Number.isInteger(r)||r<1||r>65535)throw new M("INVALID_ARGS",`Invalid Metro port: ${String(e)}. Use 1-65535.`);return r}function Y(e,t){return{platform:t,bundleUrl:P(e,t)}}function Z(e,t){return{platform:t,metroHost:q(e?.metro_host),metroPort:e?.metro_port,bundleUrl:q(e?.metro_bundle_url),launchUrl:q(e?.launch_url)}}async function ee(e){await k(e)}async function et(e,t,r={}){try{let n=await fetch(e,{headers:r,signal:AbortSignal.timeout(t)});return{ok:n.ok,status:n.status,body:await n.text()}}catch(r){if(r instanceof Error&&"TimeoutError"===r.name)throw Error(`Timed out fetching ${e} after ${t}ms`);throw r}}async function er(e,t){try{let r=await et(e,t);return r.ok&&r.body.includes("packager-status:running")}catch{return!1}}async function en(e){if(Number.isInteger(e)&&!(e<=0)){try{process.kill(e,"SIGTERM")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}if(!await s(e,1e3)){try{process.kill(e,"SIGKILL")}catch(t){let e=t.code;if("ESRCH"===e||"EPERM"===e)return;throw t}await s(e,1e3)}}}function eo(e,t){let r=Error(e);return r.retryable=t,r}function ei(e,t){return!!(e>=500||408===e||425===e||429===e||JSON.stringify(t).includes("Metro companion is not connected"))}function ea(e){return!!(e&&"object"==typeof e&&"retryable"in e&&!0===e.retryable)}async function es(e){let t;try{var r,n;t=await fetch(`${e.baseUrl}/api/metro/bridge`,{method:"POST",headers:(r=e.baseUrl,n=e.bearerToken,{Authorization:`Bearer ${n}`,"Content-Type":"application/json",...r.includes("ngrok")?{"ngrok-skip-browser-warning":"1"}:{}}),body:JSON.stringify({...e.scope,...e.runtime?{ios_runtime:e.runtime}:{},timeout_ms:e.timeoutMs}),signal:AbortSignal.timeout(e.timeoutMs)})}catch(t){if(t instanceof Error&&"TimeoutError"===t.name)throw eo(`/api/metro/bridge timed out after ${e.timeoutMs}ms calling ${e.baseUrl}/api/metro/bridge`,!0);throw eo(t instanceof Error?t.message:String(t),!0)}let o=function(e,t,r){if(!e)return{};try{let t=JSON.parse(e);if(!t||"object"!=typeof t||Array.isArray(t))throw Error("Expected a JSON object");return t}catch(i){let n=e.slice(0,200),o=i instanceof Error?i.message:String(i);throw eo(`/api/metro/bridge returned invalid JSON (${t}) from ${r}: ${o}. body=${JSON.stringify(n)}`,ei(t,e))}}(await t.text(),t.status,e.baseUrl);if(!t.ok)throw eo(`/api/metro/bridge failed (${t.status}): ${JSON.stringify(o)}`,ei(t.status,o));var i=o;let a=i.data??i;if(!a||"object"!=typeof a||Array.isArray(a))throw eo("/api/metro/bridge returned malformed descriptor: Expected a JSON object.",!1);try{return{enabled:a.enabled,baseUrl:a.base_url,statusUrl:a.status_url??"",bundleUrl:a.bundle_url??"",iosRuntime:Z(a.ios_runtime,"ios"),androidRuntime:Z(a.android_runtime,"android"),upstream:{bundleUrl:a.upstream.bundle_url??"",host:a.upstream.host??"",port:a.upstream.port??0,statusUrl:a.upstream.status_url??""},probe:{reachable:a.probe.reachable,statusCode:a.probe.status_code,latencyMs:a.probe.latency_ms,detail:a.probe.detail}}}catch(e){throw eo(`/api/metro/bridge returned malformed descriptor: ${e instanceof Error?e.message:String(e)}`,!1)}}function el(e,t,r,n,o){let i=[`Metro bridge is required for this run but could not be configured via ${e}/api/metro/bridge.`];return t&&i.push(`bridgeError=${t}`),r?.probe.reachable===!1&&i.push(`bridgeProbe=${r.probe.detail||`unreachable (status ${r.probe.statusCode||0})`}`),n&&n!==t&&i.push(`initialBridgeError=${n}`),o&&i.push(`metroCompanionLog=${o}`),i.join(" ")}async function eu(e,t,r){let n=Date.now()+t;for(;Date.now()<n;){let t=Math.min(r,Math.max(n-Date.now(),1));if(await er(e,t))return!0;let o=Math.min(500,Math.max(n-Date.now(),0));o>0&&await ee(o)}return!1}async function ec(e){let t=Date.now()+e.startupTimeoutMs,r=null,n=null;for(;Date.now()<t;){try{let t=await es({baseUrl:e.baseUrl,bearerToken:e.bearerToken,scope:e.scope,runtime:e.runtime,timeoutMs:e.probeTimeoutMs});if(!1!==t.probe.reachable)return t;r=t,n=null}catch(e){if(n=e instanceof Error?e.message:String(e),!ea(e))break}let o=Math.min(1e3,Math.max(t-Date.now(),0));o>0&&await ee(o)}throw Error(el(e.baseUrl,n,r,e.initialBridgeError,e.companionLogPath))}async function ed(r){let n=`http://${r.statusHost}:${r.metroPort}/status`;if(r.reuseExisting&&await er(n,r.probeTimeoutMs))return{started:!1,reused:!0,pid:0,statusUrl:n};let i=function(r,n,i,a,s,l){let u="expo"===n?{command:"npx",installArgs:["expo","start","--host","lan","--port",String(i)]}:{command:"npx",installArgs:["react-native","start","--host",a,"--port",String(i)]};e.mkdirSync(t.dirname(s),{recursive:!0});let c=e.openSync(s,"a"),d=0;try{d=o(u.command,u.installArgs,{cwd:r,env:l,stdio:["ignore",c,c]})}finally{e.closeSync(c)}if(!Number.isInteger(d)||d<=0)throw Error("Failed to start Metro. Expected a detached child PID.");return{pid:d}}(r.projectRoot,r.kind,r.metroPort,r.listenHost,r.logPath,r.env);if(await eu(n,r.startupTimeoutMs,r.probeTimeoutMs))return{started:!0,reused:!1,pid:i.pid,statusUrl:n};throw await en(i.pid).catch(()=>{}),Error(`Metro did not become ready at ${n} within ${r.startupTimeoutMs}ms. Check ${r.logPath}.`)}async function ep(e,t){let r=t.bridgeScope;if(!r)return null;let n=null,o=null;try{n=await es({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:r,timeoutMs:t.probeTimeoutMs})}catch(e){if(!ea(e))throw e;o=e instanceof Error?e.message:String(e)}n&&!1!==n.probe.reachable||(n=await em(e,t,r,n,o));var i=t.proxyBaseUrl,a=n;if(!a?.iosRuntime.bundleUrl)throw Error(el(i,"bridge descriptor is missing ios_runtime.metro_bundle_url",a));return n}async function em(e,t,r,n,o){let i;try{i=(await F({projectRoot:t.projectRoot,serverBaseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,bridgeScope:r,localBaseUrl:`http://${t.statusHost}:${t.metroPort}`,launchUrl:q(e.launchUrl),profileKey:q(e.companionProfileKey),consumerKey:q(e.companionConsumerKey),env:t.env})).logPath}catch(e){throw Error(el(t.proxyBaseUrl,e instanceof Error?e.message:String(e),n,o))}try{return await ec({baseUrl:t.proxyBaseUrl,bearerToken:t.proxyBearerToken,scope:r,probeTimeoutMs:t.probeTimeoutMs,startupTimeoutMs:t.startupTimeoutMs,initialBridgeError:o,companionLogPath:i})}catch(e){throw e instanceof Error?e:Error(String(e))}}async function eh(r={}){var n,o;let a=function(r){let n=r.env??process.env,o=process.cwd(),i=W(r.projectRoot??o,n,o),a=V(r.publicBaseUrl),s=V(r.proxyBaseUrl);if(!a&&!s)throw new M("INVALID_ARGS","metro prepare requires --public-base-url <url> or --proxy-base-url <url>.");let{proxyEnabled:l,proxyBaseUrl:u,proxyBearerToken:c}=function(e,t,r){let n=t||q(r.AGENT_DEVICE_METRO_BEARER_TOKEN)||"",o=n||e&&q(r.AGENT_DEVICE_DAEMON_AUTH_TOKEN)||"";if(e&&!o)throw new M("INVALID_ARGS","metro prepare requires proxy auth when --proxy-base-url is provided. Pass --bearer-token or set AGENT_DEVICE_METRO_BEARER_TOKEN or AGENT_DEVICE_DAEMON_AUTH_TOKEN.");if(!e&&n)throw new M("INVALID_ARGS","metro prepare requires --proxy-base-url when proxy auth is provided.");return{proxyEnabled:!!(e&&o),proxyBaseUrl:e,proxyBearerToken:o}}(s,q(r.proxyBearerToken)??"",n);return{env:n,projectRoot:i,kind:function(r,n){if("auto"!==n)return n;let o=function(r){let n=t.join(r,"package.json");if(!z(n))throw new M("INVALID_ARGS",`package.json not found at ${n}`);return JSON.parse(e.readFileSync(n,"utf8"))}(r);return"string"==typeof({...o.dependencies??{},...o.devDependencies??{}}).expo?"expo":"react-native"}(i,r.kind??"auto"),metroPort:X(r.metroPort??8081,8081),listenHost:q(r.listenHost)??"0.0.0.0",statusHost:q(r.statusHost)??"127.0.0.1",publicBaseUrl:a,proxyBaseUrl:u,proxyBearerToken:c,bridgeScope:l?function(e){if(!e?.tenantId||!e.runId||!e.leaseId)throw new M("INVALID_ARGS","metro prepare with proxy requires tenantId, runId, and leaseId bridge scope.");return e}(r.bridgeScope):null,startupTimeoutMs:Q(r.startupTimeoutMs,18e4,3e4),probeTimeoutMs:Q(r.probeTimeoutMs,1e4,1e3),reuseExisting:r.reuseExisting??!0,installProjectDeps:r.installDependenciesIfNeeded??!0,runtimeFilePath:r.runtimeFilePath?W(r.runtimeFilePath,n,o):null,logPath:W(r.logPath??t.join(i,".agent-device","metro.log"),n,o)}}(r),s=a.installProjectDeps?function(r,n){if(function(t){try{return e.statSync(t).isDirectory()}catch{return!1}}(t.join(r,"node_modules")))return{installed:!1};let o=z(t.join(r,"pnpm-lock.yaml"))?{command:"pnpm",installArgs:["install"]}:z(t.join(r,"yarn.lock"))?{command:"yarn",installArgs:["install"]}:{command:"npm",installArgs:["install"]};return i(o.command,o.installArgs,{cwd:r,env:n}),{installed:!0,packageManager:o.command}}(a.projectRoot,a.env):{installed:!1},l=await ed(a),{baseIosRuntime:u,baseAndroidRuntime:c}={baseIosRuntime:(n=a.publicBaseUrl)?Y(n,"ios"):{platform:"ios"},baseAndroidRuntime:n?Y(n,"android"):{platform:"android"}},d=await ep(r,a),p=d?.iosRuntime??u,m=d?.androidRuntime??c,h={projectRoot:a.projectRoot,kind:a.kind,dependenciesInstalled:s.installed,packageManager:s.packageManager??null,started:l.started,reused:l.reused,pid:l.pid,logPath:a.logPath,statusUrl:l.statusUrl,runtimeFilePath:a.runtimeFilePath,iosRuntime:p,androidRuntime:m,bridge:d};return o=a.runtimeFilePath,o&&(e.mkdirSync(t.dirname(o),{recursive:!0}),e.writeFileSync(o,JSON.stringify(h,null,2))),h}async function ef(e={}){let t=Q(e.timeoutMs,1e4,1e3),r=function(e){var t;let r,n=q(e.bundleUrl),o=n??e.runtime?.bundleUrl,i=!!n,a=!!q(o),s=l({metroHost:q(e.metroHost)??(i?void 0:q(e.runtime?.metroHost))??(a?void 0:"localhost"),metroPort:void 0!==e.metroPort?X(e.metroPort,8081):i?void 0:e.runtime?.metroPort??(a?void 0:8081),bundleUrl:o});if(!s)throw new M("INVALID_ARGS","Unable to resolve Metro host and port for reload.");return t=function(e){let t=q(e);if(!t)return"/reload";let r=new URL(t).pathname.replace(/\/+$/,"");return r.endsWith("/index.bundle")?`${r.slice(0,-13)}/reload`:"/reload"}(o),(r=new URL(`${s.scheme}://localhost`)).hostname=s.host,r.port=String(s.port),r.pathname=t,r.toString()}(e),n=await et(r,t);if(!n.ok)throw new M("COMMAND_FAILED",`Metro reload failed (${n.status}).`,{reloadUrl:r,status:n.status,body:n.body,hint:"Verify Metro is running and the target React Native app is connected to this Metro instance."});return{reloaded:!0,reloadUrl:r,status:n.status,body:n.body}}export{Y as buildMetroRuntimeHints,O as ensureCompanionTunnel,F as ensureMetroCompanion,eh as prepareMetroRuntime,ef as reloadMetro,L as stopCompanionTunnel,J as stopMetroCompanion};
|
package/dist/src/208.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"node:fs";import t from"node:path";import{AppError as n}from"./9152.js";import{resolveUserPath as r}from"./3267.js";let o=new Set(["1","true","yes","on"]),i=new Set(["0","false","no","off"]);function a(e){return`AGENT_DEVICE_${e.replace(/([A-Z])/g,"_$1").replace(/[^A-Za-z0-9_]/g,"_").toUpperCase()}`}function s(e,t,r,o){if(e.multiple)return(Array.isArray(t)?t:[t]).map(t=>s({...e,multiple:!1},t,r,o));if("boolean"===e.type){var i=t,a=r,u=o;if("boolean"==typeof i)return i;if("string"==typeof i){let e=l(i);if(void 0!==e)return e}throw new n("INVALID_ARGS",`Invalid value for "${u}" in ${a}. Expected boolean.`)}if("booleanOrString"===e.type){if("boolean"==typeof t)return t;if("string"==typeof t&&void 0!==l(t))return l(t);if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected boolean or non-empty string.`)}if("string"===e.type){if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected non-empty string.`)}if("enum"===e.type){if(void 0!==e.setValue){var
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{AppError as n}from"./9152.js";import{resolveUserPath as r}from"./3267.js";let o=new Set(["1","true","yes","on"]),i=new Set(["0","false","no","off"]);function a(e){return`AGENT_DEVICE_${e.replace(/([A-Z])/g,"_$1").replace(/[^A-Za-z0-9_]/g,"_").toUpperCase()}`}function s(e,t,r,o){if(e.multiple)return(Array.isArray(t)?t:[t]).map(t=>s({...e,multiple:!1},t,r,o));if("boolean"===e.type){var i=t,a=r,u=o;if("boolean"==typeof i)return i;if("string"==typeof i){let e=l(i);if(void 0!==e)return e}throw new n("INVALID_ARGS",`Invalid value for "${u}" in ${a}. Expected boolean.`)}if("booleanOrString"===e.type){if("boolean"==typeof t)return t;if("string"==typeof t&&void 0!==l(t))return l(t);if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected boolean or non-empty string.`)}if("string"===e.type){if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected non-empty string.`)}if("enum"===e.type){if(void 0!==e.setValue){var f=e,y=t,p=r,m=o;let i=f.setValue;if(y===i)return i;if("string"==typeof y){let e=y.trim();if(""===e||"true"===e||"1"===e)return i;if("false"===e||"0"===e)return}if(!0===y)return i;if(!1!==y)throw new n("INVALID_ARGS",`Invalid value for "${m}" in ${p}. Expected boolean-like value for enum flag.`);return}if("string"!=typeof t||!e.enumValues?.includes(t))throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected one of: ${e.enumValues?.join(", ")}.`);return t}let c="number"==typeof t?t:"string"==typeof t?Number(t):NaN;if(!Number.isFinite(c)||!Number.isInteger(c))throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected integer.`);if("number"==typeof e.min&&c<e.min)throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Must be >= ${e.min}.`);if("number"==typeof e.max&&c>e.max)throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Must be <= ${e.max}.`);return c}function l(e){let t=e.trim().toLowerCase();return!!o.has(t)||!i.has(t)&&void 0}let u=[{key:"stateDir",type:"string",path:!0},{key:"daemonBaseUrl",type:"string"},{key:"daemonAuthToken",type:"string"},{key:"daemonTransport",type:"enum",enumValues:["auto","socket","http"]},{key:"daemonServerMode",type:"enum",enumValues:["socket","http","dual"]},{key:"tenant",type:"string"},{key:"sessionIsolation",type:"enum",enumValues:["none","tenant"]},{key:"runId",type:"string"},{key:"leaseId",type:"string"},{key:"leaseBackend",type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"]},{key:"platform",type:"enum",enumValues:["ios","macos","android","linux","apple"]},{key:"target",type:"enum",enumValues:["mobile","tv","desktop"]},{key:"device",type:"string"},{key:"udid",type:"string"},{key:"serial",type:"string"},{key:"iosSimulatorDeviceSet",type:"string",path:!0,env:!1},{key:"androidDeviceAllowlist",type:"string"},{key:"session",type:"string"},{key:"metroProjectRoot",type:"string",path:!0},{key:"metroKind",type:"enum",enumValues:["auto","react-native","expo"]},{key:"metroPublicBaseUrl",type:"string"},{key:"metroProxyBaseUrl",type:"string"},{key:"metroBearerToken",type:"string"},{key:"metroPreparePort",type:"int",min:1,max:65535},{key:"metroListenHost",type:"string"},{key:"metroStatusHost",type:"string"},{key:"metroStartupTimeoutMs",type:"int",min:1},{key:"metroProbeTimeoutMs",type:"int",min:1},{key:"metroRuntimeFile",type:"string",path:!0},{key:"metroNoReuseExisting",type:"boolean"},{key:"metroNoInstallDeps",type:"boolean"}],f=new Map(u.map(e=>[e.key,e]));function y(e){let t=e.env??process.env;return r(e.configPath,{cwd:e.cwd,env:t})}function p(o){let i=function(o){let i,a,l=o.env??process.env,u=y(o);if(!e.existsSync(u))throw new n("INVALID_ARGS",`Remote config file not found: ${u}`);try{i=e.readFileSync(u,"utf8")}catch(e){throw new n("INVALID_ARGS",`Failed to read remote config file: ${u}`,{cause:e instanceof Error?e.message:String(e)})}try{a=JSON.parse(i)}catch(e){throw new n("INVALID_ARGS",`Invalid JSON in remote config file: ${u}`,{cause:e instanceof Error?e.message:String(e)})}if(!a||"object"!=typeof a||Array.isArray(a))throw new n("INVALID_ARGS",`Remote config file must contain a JSON object: ${u}`);let p={},m=a,c=t.dirname(u);for(let[e,t]of Object.entries(m)){let o=f.get(e);if(!o)throw new n("INVALID_ARGS",`Unsupported remote config key "${e}" in remote config file ${u}.`);let i=s(o,t,`remote config file ${u}`,e);p[o.key]="string"==typeof i&&"path"in o&&o.path?r(i,{cwd:c,env:l}):i}return{resolvedPath:u,profile:p}}(o);return{resolvedPath:i.resolvedPath,profile:function(...e){let t={};for(let n of e)if(n)for(let e of u){let r=n[e.key];void 0!==r&&(t[e.key]=r)}return t}(function(e=process.env){let t={};for(let n of u){let r=(function(e){let t=f.get(e);return t?.env===!1?[]:[a(e)]})(n.key).map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);r&&(t[n.key]=s(n,r.value,`environment variable ${r.name}`,r.name))}return t}(o.env),i.profile)}}export{u as REMOTE_CONFIG_FIELD_SPECS,a as buildPrimaryEnvVarName,s as parseSourceValue,y as resolveRemoteConfigPath,p as resolveRemoteConfigProfile};
|