agent-device 0.17.3 → 0.17.4
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-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.3.apk → agent-device-android-multitouch-helper-0.17.4.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.4.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.3.manifest.json → agent-device-android-multitouch-helper-0.17.4.manifest.json} +4 -4
- package/android-snapshot-helper/README.md +3 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.3.apk → agent-device-android-snapshot-helper-0.17.4.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.4.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.3.manifest.json → agent-device-android-snapshot-helper-0.17.4.manifest.json} +6 -6
- package/dist/src/123.js +1 -1
- package/dist/src/2415.js +33 -32
- package/dist/src/4012.js +4 -0
- package/dist/src/6133.js +1 -1
- package/dist/src/9542.js +5 -5
- package/dist/src/apple.js +1 -1
- package/dist/src/cli-output.js +2 -1
- package/dist/src/cli.js +4 -4
- package/dist/src/index.d.ts +16 -0
- package/dist/src/session.js +8 -8
- package/dist/src/snapshot.js +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +3 -4
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +47 -3
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +0 -9
- package/package.json +1 -1
- package/server.json +2 -2
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.3.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.3.apk.sha256 +0 -1
- package/dist/src/9238.js +0 -4
package/dist/src/snapshot.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{__webpack_require__ as e}from"./rslib-runtime.js";import{promises as t}from"node:fs";import a from"node:os";import n from"node:path";import{centerOfRect as s}from"./9616.js";import{normalizeError as o,AppError as r}from"./9152.js";import{withDiagnosticTimer as i,emitDiagnostic as l}from"./7599.js";import{pressAndroid as d,backAndroid as p}from"./input-actions.js";import{createDaemonRuntimeSessionStore as u,captureSnapshot as c,dispatchCommand as f,resolveSnapshotScope as m,runMacOsAlertAction as h,errorResponse as w,runIosRunnerCommand as g,isCommandSupportedOnDevice as y,snapshotAndroid as _,annotateScreenshotWithRefs as v,context_contextFromFlags as S}from"./2415.js";import{SETTINGS_INVALID_ARGS_MESSAGE as b,parseTimeout as I,getUnsupportedMacOsSettingMessage as A,successText as R,isMacOsSettingSupported as C,snapshotCaptureAnnotationsFrom as N}from"./6133.js";import{sleep as k}from"./4829.js";import{buildSnapshotSession as
|
|
2
|
-
${a.hint??""}`,/Android UI hierarchy dump timed out/i.test(n)||/Stock UIAutomator fallback was skipped/i.test(n)||/Android accessibility snapshots can be blocked/i.test(n)||function(e){if(!e||"object"!=typeof e)return!1;let t=String(e.errorType??""),a=String(e.message??"");return/TimeoutException/i.test(t)||/timed out/i.test(a)}(t.details?.helper)||function(e){var t;if(!e)return!1;let a=e?.timeoutMs,n=e?.cmd,s=Array.isArray(t=e?.args)?t.map(String):"string"==typeof t?t.split(/\s+/):[];return"number"==typeof a&&"adb"===n&&s.includes("uiautomator")&&s.includes("dump")}(t.details)))return{ok:!1,error:{...s,details:{...s.details??{},androidSnapshotTimeoutScreenshot:await
|
|
1
|
+
import{__webpack_require__ as e}from"./rslib-runtime.js";import{promises as t}from"node:fs";import a from"node:os";import n from"node:path";import{centerOfRect as s}from"./9616.js";import{normalizeError as o,AppError as r}from"./9152.js";import{withDiagnosticTimer as i,emitDiagnostic as l}from"./7599.js";import{pressAndroid as d,backAndroid as p}from"./input-actions.js";import{createDaemonRuntimeSessionStore as u,captureSnapshot as c,dispatchCommand as f,resolveSnapshotScope as m,runMacOsAlertAction as h,errorResponse as w,runIosRunnerCommand as g,isCommandSupportedOnDevice as y,snapshotAndroid as _,annotateScreenshotWithRefs as v,context_contextFromFlags as S}from"./2415.js";import{SETTINGS_INVALID_ARGS_MESSAGE as b,parseTimeout as I,getUnsupportedMacOsSettingMessage as A,successText as R,isMacOsSettingSupported as C,snapshotCaptureAnnotationsFrom as N}from"./6133.js";import{sleep as k}from"./4829.js";import{buildSnapshotSession as M,dispatchWaitViaRuntime as P,createDaemonRuntimePolicy as D,recordIfSession as E,resolveSessionDevice as O,withSessionlessRunnerCleanup as K}from"./selector-runtime.js";import{createAgentDevice as U}from"./123.js";import{summarizeSnapshotDiagnostics as x}from"./4012.js";var L={};e.r(L),e.d(L,{handleSnapshotCommands:()=>ew});let B=new Set(["com.android.permissioncontroller","com.google.android.permissioncontroller","com.google.android.packageinstaller","com.android.packageinstaller"]),$=new Set(["android","com.android.systemui"]),H=/^android:id\/(?:alertTitle|message|button[123]|parentPanel|buttonPanel|contentPanel)$/i,q=/^android:id\/button[123]$/i,T=/(?:^|:)id\/permission_/i,F=/\b(?:is(?:n't| not) responding|keeps stopping|has stopped|close app|app info)\b/i,j=/^(?:ok|allow|allow all|while using the app|only this time|yes|continue|save|confirm|turn on|open settings)$/i,z=/^(?:cancel|deny|don.t allow|don’t allow|not now|no|dismiss|close|close app|later|skip)$/i;function G(e,t){let a=t[0];if(!a)return;let n=V(e,a.index);for(let a of t.slice(1)){let t=new Set(V(e,a.index));for(let e=n.length-1;e>=0;e-=1)t.has(n[e])||n.splice(e,1)}return n[n.length-1]}function V(e,t){let a=new Map(e.map(e=>[e.index,e])),n=[],s=a.get(t);for(;s;)n.push(s.index),s=void 0===s.parentIndex?void 0:a.get(s.parentIndex);return n.reverse()}function W(e,t){let a=new Map;for(let t of e){if(void 0===t.parentIndex)continue;let e=a.get(t.parentIndex)??[];e.push(t),a.set(t.parentIndex,e)}let n=new Set([t]),s=[t];for(let e of s)for(let t of a.get(e)??[])n.has(t.index)||(n.add(t.index),s.push(t.index));return e.filter(e=>n.has(e.index))}function J(e){let t=e.type??"",a=e.identifier??"";return!!(e.hittable||/\bbutton\b/i.test(t)||q.test(a)||/(?:^|:)id\/permission_(?:allow|deny)/i.test(a))}function Q(e){if(!e)return"";let t=[e.label,e.value].filter(e=>"string"==typeof e&&e.trim().length>0);return t[0]?.trim()??""}async function X(e,t,a={}){if("wait"===t)return await Y(e,a.timeoutMs??1e4);if("get"===t){var n;let t=await et(e);return{kind:"alertStatus",platform:"android",action:"get",alert:n=t?.alert??null,...n?R("Alert visible"):R("No alert visible")}}return await Z(e,t)}async function Y(e,t){let a=Date.now(),n=await ee(e,t);if(!n)throw new r("COMMAND_FAILED","alert wait timed out");return{kind:"alertWait",platform:"android",action:"wait",alert:n.alert,waitedMs:Date.now()-a,...R("Alert visible")}}async function Z(e,t){var a;let n,s,o=await ee(e,2e3);if(!o)throw new r("COMMAND_FAILED","alert not found",{hint:"If a sheet is visible in snapshot but alert reports no alert, it is likely app-owned UI. Use snapshot -i and press the visible label/ref."});let i=(a=o.buttons,n="accept"===t?"accept":"dismiss",(s=a.find(e=>e.role===n))||("dismiss"===t?a.find(e=>"neutral"===e.role)??null:1===a.length?a[0]??null:null));if(i)return await d(e,i.x,i.y),ea(t,o.alert,i.label);if("dismiss"===t)return await p(e),ea(t,o.alert,"Back");throw new r("COMMAND_FAILED","alert accept found an alert but no accept button",{alert:o.alert,hint:"Inspect alert get --json for visible buttons, then use press by visible label/ref if needed."})}async function ee(e,t){let a=Date.now();for(;Date.now()-a<t;){let t=await et(e);if(t)return t;await k(300)}return null}async function et(e){return function(e){var t,a,n,o;let r,i=function(e){let t=e.filter(e=>{var t;let a;return a=(t=e).bundleId??"",B.has(a)||T.test(t.identifier??"")});if(t.length)return{nodes:t,source:"permission"};let a=function(e){let t=e.filter(e=>{var t;let a;return a=(t=e).bundleId??"",$.has(a)&&F.test(Q(t))});if(0===t.length)return[];let a=G(e,t);return void 0===a?t:W(e,a).filter(e=>e.bundleId&&$.has(e.bundleId))}(e);return a.length?{nodes:a,source:"system-dialog"}:{nodes:function(e){var t;let a,n,s=e.filter(e=>{var t;return t=e.type??"",/(?:^|[.$])[^.]*Dialog$/i.test(t)}),o=e.filter(e=>H.test(e.identifier??"")),r=s.length?[...s,...o]:(a=(t=o).some(e=>q.test(e.identifier??"")),n=t.some(e=>!q.test(e.identifier??"")),a&&n?t:[]);if(0===r.length)return[];let i=G(e,r);return void 0===i?r:W(e,i)}(e),source:"native-dialog"}}(e),l=i.nodes;if(0===l.length)return null;let d=function(e){let t=new Set,a=[];for(let n of e){let e=Q(n);if(!e||!n.rect||!J(n))continue;let o=e.trim().toLowerCase();if(!o||t.has(o))continue;t.add(o);let r=s(n.rect);a.push({label:e,x:r.x,y:r.y,role:function(e,t){var a;let n=(a=e.identifier??"",/(?:^|:)id\/button1$/i.test(a)?"accept":/(?:^|:)id\/button2$/i.test(a)?"dismiss":/(?:^|:)id\/button3$/i.test(a)?"neutral":/(?:^|:)id\/permission_allow/i.test(a)?"accept":/(?:^|:)id\/permission_deny/i.test(a)?"dismiss":null);return n||(j.test(t.trim())?"accept":z.test(t.trim())?"dismiss":"neutral")}(n,e)})}return a}(l),p=l.filter(e=>Q(e)&&!J(e)),u=Q((t=p).find(e=>/(?:^|:)id\/(?:alertTitle|permission_message)$/i.test(e.identifier??"")))||Q(t[0]),c=(a=p,n=u,(r=a.map(e=>Q(e)).filter(e=>e&&e!==n)).length?[...new Set(r)].join("\n"):void 0),f=(o=l,o.find(e=>e.bundleId)?.bundleId);return{alert:{...u?{title:u}:{},...c?{message:c}:{},buttons:d.map(e=>e.label),platform:"android",source:i.source,...f?{packageName:f}:{}},buttons:d}}((await i("snapshot_capture",async()=>await _(e,{helperWaitForIdleTimeoutMs:0,includeHiddenContentHints:!1}),{backend:"android",purpose:"alert"})).nodes)}function ea(e,t,a){return{kind:"alertHandled",platform:"android",action:e,handled:!0,alert:t,button:a,...R(`Alert ${e}ed`)}}async function en(e){var t;let{req:a,logPath:n,session:s,device:o}=e,r="accept"===(t=a.positionals?.[0])||"dismiss"===t||"wait"===t?t:"get",i=s?"frontmost-app"===s.surface?{surface:"frontmost-app"}:{bundleId:s.appBundleId,surface:s.surface}:{};if(!y("alert",o))return w("UNSUPPORTED_OPERATION","alert is not supported on this device");if("android"===o.platform){let t=I(a.positionals?.[1])??1e4;return ei(e,await X(o,r,{timeoutMs:t}))}if("macos"===o.platform){let t=async e=>await h(e,i);return await es(e,r,t)}let l={verbose:a.flags?.verbose,logPath:n,traceLogPath:s?.trace?.outPath,requestId:a.meta?.requestId},d=async e=>await g(o,{command:"alert",action:e,appBundleId:s?.appBundleId},l);return await es(e,r,d)}async function es(e,t,a){if("wait"===t)return await eo(e,a);let n="accept"===t||"dismiss"===t?t:"get";return"accept"===n||"dismiss"===n?await er(e,n,a):ei(e,await a("get"))}async function eo(e,t){let a=I(e.req.positionals?.[1])??1e4,n=Date.now();for(;Date.now()-n<a;){try{return ei(e,await t("get"))}catch{}await k(300)}return w("COMMAND_FAILED","alert wait timed out")}async function er(e,t,a){var n,s;let o,i,l=Date.now();for(;Date.now()-l<2e3;){try{return ei(e,await a(t))}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await k(300)}throw(n=i)instanceof r&&(s=n,(o=String(s?.message??"").toLowerCase()).includes("alert not found")||o.includes("no alert"))?new r(n.code,n.message,{...n.details??{},hint:"If the permission sheet is visible in snapshot or screenshot but alert reports no alert, take a scoped snapshot around the visible button label and use press @ref."}):n}function ei(e,t){return E(e.sessionStore,e.session,e.req,t),{ok:!0,data:t}}async function el(e){let{req:t,logPath:a,sessionStore:n,session:s,device:o,parsed:r}=e,{setting:i,state:l,appBundleId:d,permissionTarget:p,latitude:u,longitude:c}=r;if(!y("settings",o))return w("UNSUPPORTED_OPERATION","settings is not supported on this device");if("macos"===o.platform&&!C(i))return w("INVALID_ARGS",A(i));let m=d??s?.appBundleId;if("clear-app-state"===i&&!m)return w("INVALID_ARGS","settings clear-app-state requires an app id when no app is bound to the session");let h="clear-app-state"===i?[i,l,m??""]:"permission"===i?[i,l,p??"",t.positionals?.[3]??"",m??""]:"location"===i&&"set"===l?[i,l,u??"",c??"",m??""]:[i,l,m??""],g=await f(o,"settings",h,t.flags?.out,{...S(a,t.flags,m,s?.trace?.outPath)});return E(n,s,t,g??{setting:i,state:l}),{ok:!0,data:g??{setting:i,state:l}}}async function ed(e){var t,a;let n;if("snapshot"!==e.command||"android"!==e.device.platform)return;let s=o(e.error);if("COMMAND_FAILED"===(t=s).code&&(a=t,n=`${a.message}
|
|
2
|
+
${a.hint??""}`,/Android UI hierarchy dump timed out/i.test(n)||/Stock UIAutomator fallback was skipped/i.test(n)||/Android accessibility snapshots can be blocked/i.test(n)||function(e){if(!e||"object"!=typeof e)return!1;let t=String(e.errorType??""),a=String(e.message??"");return/TimeoutException/i.test(t)||/timed out/i.test(a)}(t.details?.helper)||function(e){var t;if(!e)return!1;let a=e?.timeoutMs,n=e?.cmd,s=Array.isArray(t=e?.args)?t.map(String):"string"==typeof t?t.split(/\s+/):[];return"number"==typeof a&&"adb"===n&&s.includes("uiautomator")&&s.includes("dump")}(t.details)))return{ok:!1,error:{...s,details:{...s.details??{},androidSnapshotTimeoutScreenshot:await ep(e)}}}}async function ep(e){try{var s,r,i;let o=await t.mkdtemp(n.join(a.tmpdir(),"agent-device-android-snapshot-timeout-")),d=n.join(o,"snapshot-timeout-overlay-refs.png"),p=(s=await f(e.device,"screenshot",[d],void 0,{...S(e.logPath,{screenshotNoStabilize:!0},e.session?.appBundleId,e.session?.trace?.outPath),surface:e.session?.surface}),r=d,(i=s,"object"==typeof i&&null!==i&&"path"in i&&"string"==typeof i.path)?s.path:r);await t.access(p);let u=await eu(p,e.session);return l({level:"warn",phase:"android_snapshot_timeout_screenshot_captured",data:{path:p,overlayRefCount:"overlayRefCount"in u?u.overlayRefCount:void 0,overlayRefsAnnotated:"overlayRefsAnnotated"in u?u.overlayRefsAnnotated:void 0}}),u}catch(t){let e=o(t);return l({level:"warn",phase:"android_snapshot_timeout_screenshot_failed",data:{error:e.message}}),{captureFailed:!0,error:e.message}}}async function eu(e,t){if(!t?.snapshot)return{path:e,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:"unavailable",overlayRefCount:0};try{let a=await v({screenshotPath:e,snapshot:t.snapshot});return{path:e,overlayRefsRequested:!0,overlayRefsAnnotated:a.length>0,overlayRefCount:a.length,overlayRefSource:"session-snapshot",overlayRefs:a}}catch(a){let t=o(a);return l({level:"warn",phase:"android_snapshot_timeout_screenshot_overlay_failed",data:{path:e,error:t.message}}),{path:e,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:"session-snapshot",overlayRefCount:0,overlayAnnotationError:t.message}}}async function ec(e){return await em({...e,command:"snapshot",unsupportedMessage:"snapshot is not supported on this device",execute:async({runtime:e,sessionName:t,req:a,snapshotScope:n})=>{let s=await e.capture.snapshot({session:t,interactiveOnly:a.flags?.snapshotInteractiveOnly,depth:a.flags?.snapshotDepth,scope:n,raw:a.flags?.snapshotRaw,forceFull:a.flags?.snapshotForceFull});return{data:s,record:{kind:"snapshot",nodes:s.nodes.length,truncated:s.truncated}}}})}async function ef(e){return await em({...e,command:"diff",unsupportedMessage:"diff is not supported on this device",execute:async({runtime:e,sessionName:t,req:a,snapshotScope:n})=>{let s=await e.capture.diffSnapshot({session:t,interactiveOnly:a.flags?.snapshotInteractiveOnly,depth:a.flags?.snapshotDepth,scope:n,raw:a.flags?.snapshotRaw});return{data:s,record:{kind:"diff",mode:"snapshot",baselineInitialized:s.baselineInitialized,summary:s.summary}}}})}async function em(e){var t,a;let{req:n,sessionName:s,logPath:o,sessionStore:i}=e,{session:l,device:d}=await O(i,s,n.flags);if(!y(e.command,d))return w("UNSUPPORTED_OPERATION",e.unsupportedMessage);let p=m(n.flags?.snapshotScope,l);if(!p.ok)return p;let f=(t=e.command,a=l,"ios"!==d.platform||a?.appBundleId?null:w("SESSION_NOT_FOUND",`iOS ${t} requires an active app session on the target device. Run open first (for example: open --session ${a?.name??"sim"} --platform ios --device "<name>" <app>).`));return f||await K(l,d,async()=>{var t,a;let f,m,h=function(e){let{req:t,sessionName:a,logPath:n,sessionStore:s,session:o,device:i,snapshotScope:l}=e;return U({backend:function(e){let{req:t,logPath:a,session:n,device:s,snapshotScope:o}=e;return{platform:s.platform,captureSnapshot:async(e,r)=>{let i=await c({device:s,session:n,flags:t.flags,outPath:r?.outPath??t.flags?.out,logPath:a,snapshotScope:o}),l=x(n);return{snapshot:i.snapshot,...N(i),...l?{snapshotDiagnostics:l}:{},appName:n?.appBundleId?n.appName??n.appBundleId:void 0,appBundleId:n?.appBundleId}}}}({req:t,logPath:n,session:o,device:i,snapshotScope:l}),...D("snapshot"),sessions:u({sessionName:a,getSession:()=>s.get(a),recordOptions:{includeSnapshot:!0},setRecord:e=>{var n;let o=function(e){if(!e.snapshot)throw new r("UNKNOWN","snapshot runtime did not produce session state");return e}(e),l=s.get(a);s.set(a,function(e){var t,a;let{current:n,sessionName:s,device:o,record:r,refScopedSnapshot:i}=e,l=(t=n,a=r,i&&a.snapshot?.nodes.length===0&&t?.snapshot!==void 0),d=l?n.snapshot:r.snapshot,p=M({session:n,sessionName:s,device:o,snapshot:d,appBundleId:r.appBundleId});return p.snapshotScopeSource=function(e){let{current:t,keepCurrentSnapshot:a,refScopedSnapshot:n}=e;if(n)return a?t?.snapshotScopeSource:t?.snapshotScopeSource??t?.snapshot}({current:n,keepCurrentSnapshot:l,refScopedSnapshot:i}),r.appName&&(p.appName=r.appName),p}({current:l,sessionName:a,device:i,record:o,refScopedSnapshot:(n=t,n.flags?.snapshotScope?.trim().startsWith("@")===!0)}))}})})}({req:n,sessionName:s,logPath:o,sessionStore:i,session:l,device:d,snapshotScope:p.scope});try{m=await e.execute({runtime:h,sessionName:s,req:n,snapshotScope:p.scope})}catch(a){let t=await ed({error:a,command:e.command,logPath:o,session:l,device:d});if(!t)throw a;return t}return(f=(t={req:n,sessionName:s,sessionStore:i,result:m.record}).sessionStore.get(t.sessionName))&&t.sessionStore.recordAction(f,{command:t.req.command,positionals:t.req.positionals??[],flags:t.req.flags??{},result:"snapshot"===(a=t.result).kind?{nodes:a.nodes,truncated:a.truncated}:{mode:a.mode,baselineInitialized:a.baselineInitialized,summary:a.summary}}),{ok:!0,data:m.data}})}let eh={snapshot:async({req:e,sessionName:t,logPath:a,sessionStore:n})=>await ec({req:e,sessionName:t,logPath:a,sessionStore:n}),diff:async({req:e,sessionName:t,logPath:a,sessionStore:n})=>e.positionals?.[0]!=="snapshot"?w("INVALID_ARGS","diff currently supports only: diff snapshot"):await ef({req:e,sessionName:t,logPath:a,sessionStore:n}),wait:async({req:e,sessionName:t,logPath:a,sessionStore:n})=>await P({req:e,sessionName:t,logPath:a,sessionStore:n}),alert:async({req:e,sessionName:t,logPath:a,sessionStore:n})=>{let{session:s,device:o}=await O(n,t,e.flags);return await K(s,o,async()=>await en({req:e,logPath:a,sessionStore:n,session:s,device:o}))},settings:async({req:e,sessionName:t,logPath:a,sessionStore:n})=>{let s,o,r,i=(s=e.positionals?.[0]?.toLowerCase(),o=e.positionals?.[1]?.toLowerCase(),r=e.positionals?.[2]?.toLowerCase(),"clear-app-state"===s?{ok:!0,parsed:{setting:s,state:"clear",appBundleId:"clear"===o?e.positionals?.[2]:e.positionals?.[1]}}:s&&o&&("permission"!==s||r)&&("location"!==s||"set"!==o||e.positionals?.[2]&&e.positionals?.[3])?{ok:!0,parsed:{setting:s,state:o,permissionTarget:r,latitude:e.positionals?.[2],longitude:e.positionals?.[3]}}:w("INVALID_ARGS",b));if(!i.ok)return i;let{session:l,device:d}=await O(n,t,e.flags);return await K(l,d,async()=>await el({req:e,logPath:a,sessionStore:n,session:l,device:d,parsed:i.parsed}))}};async function ew(e){let t=eh[e.req.command];return t?await t(e):null}export{L as snapshot_namespaceObject};
|
package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift
CHANGED
|
@@ -49,10 +49,9 @@ extension RunnerTests {
|
|
|
49
49
|
return nil
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
// own frame is the reliable screen rect here.
|
|
52
|
+
// If the app frame is unavailable, the private root's own frame is the reliable screen
|
|
53
|
+
// rect here. Avoid public window queries: stale transient windows can record XCTest
|
|
54
|
+
// failures after the runner already returned a successful command response.
|
|
56
55
|
var viewport = safeSnapshotViewport(app: app)
|
|
57
56
|
let rootFrame = privateAXRect(root["frame"])
|
|
58
57
|
if viewport.isInfinite || viewport.isNull || viewport.isEmpty, !rootFrame.isEmpty {
|
package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift
CHANGED
|
@@ -13,7 +13,7 @@ extension RunnerTests {
|
|
|
13
13
|
return (gestureStartUptimeMs, currentUptimeMs())
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
func synthesizedSwipeFallbackHoldDuration(durationMs: Double) -> TimeInterval {
|
|
17
17
|
min(max((durationMs / 5.0) / 1000.0, 0.016), 0.120)
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -157,8 +157,8 @@ struct SequenceStep: Codable {
|
|
|
157
157
|
let y2: Double?
|
|
158
158
|
let durationMs: Double?
|
|
159
159
|
let pauseMs: Double?
|
|
160
|
-
/// For `tap` steps on iOS non-tv: use the synthesized HID
|
|
161
|
-
///
|
|
160
|
+
/// For `tap`/`drag` steps on iOS non-tv: use the synthesized HID fast path instead of the
|
|
161
|
+
/// drag-based XCUICoordinate path, matching the individual command behavior.
|
|
162
162
|
let synthesized: Bool?
|
|
163
163
|
}
|
|
164
164
|
|
package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift
CHANGED
|
@@ -164,6 +164,50 @@ extension RunnerTests {
|
|
|
164
164
|
}
|
|
165
165
|
// Synthesis unsupported (e.g. macOS) — fall through to the drag-based tapAt below.
|
|
166
166
|
}
|
|
167
|
+
if step.kind == "drag", step.synthesized == true {
|
|
168
|
+
let dragPoints = keyboardAvoidingDragPoints(
|
|
169
|
+
app: activeApp, x: x, y: y, x2: step.x2 ?? x, y2: step.y2 ?? y)
|
|
170
|
+
let durationMs = min(max(step.durationMs ?? 250, 16), 10000)
|
|
171
|
+
let (timing, outcome) = performGesture(activeApp, idleTimeout: false) {
|
|
172
|
+
synthesizedDragAt(
|
|
173
|
+
app: activeApp,
|
|
174
|
+
x: dragPoints.x,
|
|
175
|
+
y: dragPoints.y,
|
|
176
|
+
x2: dragPoints.x2,
|
|
177
|
+
y2: dragPoints.y2,
|
|
178
|
+
durationMs: durationMs
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
if case .performed = outcome {
|
|
182
|
+
if let pauseMs = step.pauseMs, pauseMs > 0 {
|
|
183
|
+
sleepFor(min(max(pauseMs, 0), 10000) / 1000.0)
|
|
184
|
+
}
|
|
185
|
+
return SequenceStepOutcome(
|
|
186
|
+
outcome: outcome,
|
|
187
|
+
gestureStartUptimeMs: timing.gestureStartUptimeMs,
|
|
188
|
+
gestureEndUptimeMs: timing.gestureEndUptimeMs
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
let fallbackHoldDuration = synthesizedSwipeFallbackHoldDuration(durationMs: step.durationMs ?? 250)
|
|
192
|
+
let (fallbackTiming, fallbackOutcome) = performGesture(activeApp) {
|
|
193
|
+
dragAt(
|
|
194
|
+
app: activeApp,
|
|
195
|
+
x: dragPoints.x,
|
|
196
|
+
y: dragPoints.y,
|
|
197
|
+
x2: dragPoints.x2,
|
|
198
|
+
y2: dragPoints.y2,
|
|
199
|
+
holdDuration: fallbackHoldDuration
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
if case .performed = fallbackOutcome, let pauseMs = step.pauseMs, pauseMs > 0 {
|
|
203
|
+
sleepFor(min(max(pauseMs, 0), 10000) / 1000.0)
|
|
204
|
+
}
|
|
205
|
+
return SequenceStepOutcome(
|
|
206
|
+
outcome: fallbackOutcome,
|
|
207
|
+
gestureStartUptimeMs: fallbackTiming.gestureStartUptimeMs,
|
|
208
|
+
gestureEndUptimeMs: fallbackTiming.gestureEndUptimeMs
|
|
209
|
+
)
|
|
210
|
+
}
|
|
167
211
|
let (timing, outcome) = performGesture(activeApp) {
|
|
168
212
|
switch step.kind {
|
|
169
213
|
case "doubleTap":
|
|
@@ -173,9 +217,9 @@ extension RunnerTests {
|
|
|
173
217
|
let duration = min(max(step.durationMs ?? 800, 16), 10000) / 1000.0
|
|
174
218
|
return longPressAt(app: activeApp, x: x, y: y, duration: duration)
|
|
175
219
|
case "drag":
|
|
176
|
-
// Route through keyboardAvoidingDragPoints for parity with the individual `.drag` command
|
|
177
|
-
//
|
|
178
|
-
//
|
|
220
|
+
// Route through keyboardAvoidingDragPoints for parity with the individual `.drag` command.
|
|
221
|
+
// The non-synthesized coordinate-drag path ignores durationMs, matching that command's
|
|
222
|
+
// non-synthesized branch.
|
|
179
223
|
let dragPoints = keyboardAvoidingDragPoints(
|
|
180
224
|
app: activeApp, x: x, y: y, x2: step.x2 ?? x, y2: step.y2 ?? y)
|
|
181
225
|
return dragAt(
|
|
@@ -739,15 +739,6 @@ extension RunnerTests {
|
|
|
739
739
|
}
|
|
740
740
|
|
|
741
741
|
private func snapshotViewport(app: XCUIApplication) -> CGRect {
|
|
742
|
-
let windows = app.windows.allElementsBoundByIndex
|
|
743
|
-
let windowFrames = windows
|
|
744
|
-
.filter { $0.exists && !$0.frame.isNull && !$0.frame.isEmpty }
|
|
745
|
-
.map(\.frame)
|
|
746
|
-
if let largestWindowFrame = windowFrames.max(by: { left, right in
|
|
747
|
-
left.width * left.height < right.width * right.height
|
|
748
|
-
}) {
|
|
749
|
-
return largestWindowFrame
|
|
750
|
-
}
|
|
751
742
|
let appFrame = app.frame
|
|
752
743
|
if !appFrame.isNull && !appFrame.isEmpty {
|
|
753
744
|
return appFrame
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-device",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
4
4
|
"description": "Agent-native CLI for AI mobile testing and app automation across iOS, Android, tvOS, Android TV, macOS, and Linux.",
|
|
5
5
|
"mcpName": "io.github.callstackincubator/agent-device",
|
|
6
6
|
"license": "MIT",
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/callstackincubator/agent-device",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.17.
|
|
10
|
+
"version": "0.17.4",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "agent-device",
|
|
15
|
-
"version": "0.17.
|
|
15
|
+
"version": "0.17.4",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|
package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.3.apk.sha256
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
6989d98eafa3826bd53b5d36268b5c96f2c9404f87478d0b541139c25783c26a agent-device-android-multitouch-helper-0.17.3.apk
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
522875a8a672915e05710a4b15fb51162de206824f4a19a43028d184b337a76d agent-device-android-snapshot-helper-0.17.3.apk
|
package/dist/src/9238.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import e from"node:crypto";import t from"node:fs";import n from"node:path";import{resolveUserPath as r,expandUserHomePath as o}from"./3267.js";import{findProjectRoot as s}from"./9671.js";function i(l,a={}){var u,c;let f,p=(u=l,c=a,(f=(u??"").trim())?r(f,{env:c.env}):function(r={}){var i;let l,a,u,c=n.join(o("~",{env:r.env}),".agent-device"),f=r.projectRoot??s();return(i=f,t.existsSync(n.join(i,"package.json"))&&t.existsSync(n.join(i,"src","daemon.ts")))?n.join(c,"dev",(l=function(e){try{return t.realpathSync.native(e)}catch{return n.resolve(e)}}(f),a=n.basename(l).replaceAll(/[^a-zA-Z0-9._-]+/g,"-"),u=e.createHash("sha1").update(l).digest("hex").slice(0,12),`${a||"agent-device"}-${u}`)):c}(c));return{baseDir:p,infoPath:n.join(p,"daemon.json"),lockPath:n.join(p,"daemon.lock"),logPath:n.join(p,"daemon.log"),sessionsDir:n.join(p,"sessions")}}function l(e){let t=(e??"").trim().toLowerCase();return"http"===t?"http":"dual"===t?"dual":"socket"}function a(e){let t=(e??"").trim().toLowerCase();return"auto"===t?"auto":"socket"===t?"socket":"http"===t?"http":"auto"}function u(e){return"tenant"===(e??"").trim().toLowerCase()?"tenant":"none"}function c(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}let f=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,p=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,m=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function d(){let e=process.argv[1];return e?h(e):"unknown"}function h(r,o=s()){try{let s=n.resolve(o),i=[n.resolve(r)],l=new Set,a=[];for(;i.length>0;){let e=i.pop();if(!e||l.has(e))continue;l.add(e);let r=t.statSync(e);if(!r.isFile())continue;let o=n.relative(s,e)||e;a.push(`${o}:${r.size}:${Math.trunc(r.mtimeMs)}`);let u=t.readFileSync(e,"utf8");for(let t of function(e){let t=new Set;return v(e,f,t),v(e,p,t),[...t]}(u)){let r=function(e,t){let r=n.resolve(n.dirname(e),t),o=g(r);if(o)return o;for(let e of m){let t=g(`${r}${e}`);if(t)return t}for(let e of m){let t=g(n.join(r,`index${e}`));if(t)return t}return null}(e,t);r&&i.push(r)}}let u=a.sort().join("|"),c=e.createHash("sha1").update(u).digest("hex");return`graph:${a.length}:${c}`}catch{return"unknown"}}function v(e,t,n){t.lastIndex=0;let r=null;for(;null!==(r=t.exec(e));){let e=r[1]?.trim();e?.startsWith(".")&&n.add(e)}}function g(e){try{return t.statSync(e).isFile()?e:null}catch{return null}}let y=/^[A-Za-z0-9_@%+=:,./-]+$/;function S(e){return`'${e.replaceAll("'","'\\''")}'`}function j(e){return y.test(e)?e:S(e)}function $(e,t){let n=[],r=e+t.toString(),o=r.indexOf("\n");for(;-1!==o;){let e=r.slice(0,o).trim();r=r.slice(o+1),e&&n.push(e),o=r.indexOf("\n")}return{lines:n,buffer:r}}function x(e){return e.meta?.requestProgress==="replay-test"}function _(e){return!!e&&"object"==typeof e&&"progress"===e.type&&!!e.event}function D(e){return!!e&&"object"==typeof e&&"response"===e.type&&!!e.response}function P(e){return`${JSON.stringify({type:"progress",event:e})}
|
|
2
|
-
`}function C(e){return`${JSON.stringify({type:"response",response:e})}
|
|
3
|
-
`}function k(e){return`${JSON.stringify({type:"response",response:e})}
|
|
4
|
-
`}export{h as computeDaemonCodeSignature,$ as consumeTextLines,_ as isDaemonProgressEnvelope,D as isDaemonResponseEnvelope,c as normalizeTenantId,d as resolveDaemonCodeSignature,i as resolveDaemonPaths,l as resolveDaemonServerMode,a as resolveDaemonTransportPreference,u as resolveSessionIsolationMode,P as serializeDaemonProgressEnvelope,C as serializeDaemonResponseEnvelope,k as serializeDaemonRpcResponseEnvelope,S as shellQuote,j as shellQuoteIfNeeded,x as shouldStreamRequestProgress};
|