1- import fs from 'node:fs' ;
2- import path from 'node:path' ;
31import type { ProviderPluginHost } from 'agent-device/plugins' ;
42import type { CliFlags } from '@agent-device/contracts/command' ;
53import {
64 rejectRefusedProviderProfileFields ,
5+ requireResolvedProfilePlatform ,
6+ requireResolvedProfileValue ,
77 type ProviderProfileFieldDeclaration ,
88} from '@agent-device/contracts/provider-profile-fields' ;
9- import { canonicalTestMuAppReference , isTestMuAppReference } from './providers.ts' ;
9+ import {
10+ requireConnectFlag ,
11+ requireConnectPlatform ,
12+ resolveLocalAppArtifact ,
13+ } from '@agent-device/provider-webdriver/plugin' ;
14+ import {
15+ canonicalTestMuAppReference ,
16+ isTestMuAppReference ,
17+ requireTestMuCredentials ,
18+ } from './providers.ts' ;
1019import { verifyTestMuConnection } from './testmu-connection-verification.ts' ;
1120import { readTestMuDeviceFeatureFields , readTestMuDeviceType } from './testmu-device-features.ts' ;
1221
22+ const PROVIDER = 'testmu' ;
23+ const SERVICE = 'TestMu AI' ;
24+
1325export function createTestMuConnection (
1426 host : ProviderPluginHost ,
1527 fields : ProviderProfileFieldDeclaration ,
1628) {
17- const required = ( value : string | undefined , name : string ) => {
18- if ( value ?. trim ( ) ) return value ;
19- throw host . createError ( 'INVALID_ARGS' , `connect testmu requires ${ name } .` ) ;
20- } ;
2129 return {
2230 resolve : ( { flags, cwd } : { flags : CliFlags ; cwd : string } ) => {
2331 rejectRefusedProviderProfileFields ( flags , fields ) ;
24- required ( host . env . LT_USERNAME , 'LT_USERNAME' ) ;
25- required ( host . env . LT_ACCESS_KEY , 'LT_ACCESS_KEY' ) ;
26- if ( flags . platform !== 'android' && flags . platform !== 'ios' )
27- throw host . createError ( 'INVALID_ARGS' , 'connect testmu requires --platform ios|android.' ) ;
28- let app = canonicalTestMuAppReference (
29- required ( flags . providerApp , '--provider-app <lt://app-id, URL, or local path>' ) ,
32+ requireTestMuCredentials ( host . env , `connect ${ PROVIDER } ` ) ;
33+ const platform = requireConnectPlatform ( flags , PROVIDER ) ;
34+ const app = connectAppReference (
35+ requireConnectFlag (
36+ flags . providerApp ,
37+ PROVIDER ,
38+ '--provider-app <lt://app-id, URL, or local path>' ,
39+ ) ,
40+ cwd ,
41+ host ,
3042 ) ;
31- if ( app . startsWith ( 'lt://' ) ) {
32- if ( ! isTestMuAppReference ( app ) )
33- throw host . createError (
34- 'INVALID_ARGS' ,
35- 'connect testmu requires a valid lt:// app reference.' ,
36- ) ;
37- } else if ( ! / ^ h t t p s ? : \/ \/ / i. test ( app ) ) {
38- app = path . resolve ( cwd , app ) ;
39- if ( ! fs . statSync ( app , { throwIfNoEntry : false } ) ?. isFile ( ) )
40- throw host . createError ( 'INVALID_ARGS' , `TestMu AI app file not found: ${ app } ` ) ;
41- }
4243 return {
4344 profile : {
44- leaseProvider : 'testmu' ,
45- leaseBackend :
46- flags . leaseBackend ?? ( flags . platform === 'ios' ? 'ios-instance' : 'android-instance' ) ,
47- platform : flags . platform ,
48- device : required ( flags . device , '--device <name>' ) ,
49- providerOsVersion : required ( flags . providerOsVersion , '--provider-os-version <version>' ) ,
45+ leaseProvider : PROVIDER ,
46+ platform,
47+ device : requireConnectFlag ( flags . device , PROVIDER , '--device <name>' ) ,
48+ providerOsVersion : requireConnectFlag (
49+ flags . providerOsVersion ,
50+ PROVIDER ,
51+ '--provider-os-version <version>' ,
52+ ) ,
5053 providerApp : app ,
5154 providerDeviceType : readTestMuDeviceType ( flags ) ,
5255 providerProject : flags . providerProject ,
@@ -57,23 +60,36 @@ export function createTestMuConnection(
5760 extraFlags : { providerApp : app } ,
5861 } ;
5962 } ,
60- verify : async ( { flags } : { flags : CliFlags } ) => {
61- if ( flags . platform !== 'android' && flags . platform !== 'ios' )
62- throw host . createError ( 'INVALID_ARGS' , 'TestMu profile missed platform.' ) ;
63- return await verifyTestMuConnection (
63+ verify : async ( { flags } : { flags : CliFlags } ) =>
64+ await verifyTestMuConnection (
6465 {
65- provider : 'testmu' ,
66- username : required ( host . env . LT_USERNAME , 'LT_USERNAME' ) ,
67- accessKey : required ( host . env . LT_ACCESS_KEY , 'LT_ACCESS_KEY' ) ,
68- platform : flags . platform ,
69- deviceName : required ( flags . device , '--device' ) ,
70- osVersion : required ( flags . providerOsVersion , '--provider-os-version' ) ,
71- app : canonicalTestMuAppReference ( required ( flags . providerApp , '--provider-app' ) ) ,
66+ provider : PROVIDER ,
67+ ...requireTestMuCredentials ( host . env , `connect ${ PROVIDER } ` ) ,
68+ platform : requireResolvedProfilePlatform ( flags . platform , SERVICE ) ,
69+ deviceName : requireResolvedProfileValue ( flags . device , 'TestMu AI profile missed device.' ) ,
70+ osVersion : requireResolvedProfileValue (
71+ flags . providerOsVersion ,
72+ 'TestMu AI profile missed OS version.' ,
73+ ) ,
74+ app : canonicalTestMuAppReference (
75+ requireResolvedProfileValue ( flags . providerApp , 'TestMu AI profile missed app.' ) ,
76+ ) ,
7277 deviceType : readTestMuDeviceType ( flags ) ,
7378 apiEndpoint : host . env . TESTMU_API_ENDPOINT ,
7479 } ,
7580 host . clientVersion ,
76- ) ;
77- } ,
81+ ) ,
7882 } ;
7983}
84+
85+ /** An `lt://` id is canonicalized, a public URL passes through, and anything else must be a local file. */
86+ function connectAppReference ( app : string , cwd : string , host : ProviderPluginHost ) : string {
87+ const reference = canonicalTestMuAppReference ( app ) ;
88+ if ( reference . startsWith ( 'lt://' ) ) {
89+ if ( isTestMuAppReference ( reference ) ) return reference ;
90+ throw host . createError ( 'INVALID_ARGS' , 'connect testmu requires a valid lt:// app reference.' ) ;
91+ }
92+ return / ^ h t t p s ? : \/ \/ / i. test ( reference )
93+ ? reference
94+ : resolveLocalAppArtifact ( reference , cwd , SERVICE ) ;
95+ }
0 commit comments